Greatly improve performance for type checking large, type-annotated, array literal expressions by directly applying contextual type information to its constituent element expressions. (rdar://problem/16736884)

There's a lot more that can be done with this, but for now this change will make the OpenGLES template usable.

Swift SVN r18353
This commit is contained in:
Joe Pamer
2014-05-18 21:27:41 +00:00
parent 94d5c81b4b
commit a22b391e2a
10 changed files with 84 additions and 19 deletions

View File

@@ -2177,7 +2177,8 @@ namespace {
SourceLoc(), /*implicit*/ true); SourceLoc(), /*implicit*/ true);
Expr *metaty = TypeExpr::createImplicit(baseElementType, tc.Context); Expr *metaty = TypeExpr::createImplicit(baseElementType, tc.Context);
Expr *applyExpr = new(tc.Context) ConstructorRefCallExpr(ctor, metaty); Expr *applyExpr = new(tc.Context) ConstructorRefCallExpr(ctor, metaty);
if (tc.typeCheckExpression(applyExpr, dc, Type(), /*discarded*/ false)) if (tc.typeCheckExpression(applyExpr, dc, Type(), Type(),
/*discarded*/ false))
llvm_unreachable("should not fail"); llvm_unreachable("should not fail");
expr->setConstructionFunction(applyExpr); expr->setConstructionFunction(applyExpr);
@@ -2870,7 +2871,7 @@ static Expr *getCallerDefaultArg(TypeChecker &tc, DeclContext *dc,
// literal expression. // literal expression.
Expr *init = new (tc.Context) MagicIdentifierLiteralExpr(magicKind, loc, Expr *init = new (tc.Context) MagicIdentifierLiteralExpr(magicKind, loc,
/*Implicit=*/true); /*Implicit=*/true);
bool invalid = tc.typeCheckExpression(init, dc, defArg.second, bool invalid = tc.typeCheckExpression(init, dc, defArg.second, Type(),
/*discardedExpr=*/false); /*discardedExpr=*/false);
assert(!invalid && "conversion cannot fail"); assert(!invalid && "conversion cannot fail");
(void)invalid; (void)invalid;

View File

@@ -542,6 +542,34 @@ namespace {
C.getIdentifier("Element")).front()); C.getIdentifier("Element")).front());
auto locator = CS.getConstraintLocator(expr); auto locator = CS.getConstraintLocator(expr);
auto contextualType = CS.getContextualType(expr);
Type *contextualArrayType = nullptr;
Type contextualArrayElementType = nullptr;
// If a contextual type exists for this expression, apply it directly.
if (contextualType && CS.isArrayType(*contextualType)) {
// Is the array type a contextual type
contextualArrayType = contextualType;
contextualArrayElementType =
CS.getBaseTypeForArrayType(contextualType->getPointer());
CS.addConstraint(ConstraintKind::ConformsTo, *contextualType,
arrayProto->getDeclaredType(),
locator);
unsigned index = 0;
for (auto element : expr->getElements()) {
CS.addConstraint(ConstraintKind::Conversion,
element->getType(),
contextualArrayElementType,
CS.getConstraintLocator(expr,
LocatorPathElt::
getTupleElement(index++)));
}
return *contextualArrayType;
}
auto arrayTy = CS.createTypeVariable(locator, TVO_PrefersSubtypeBinding); auto arrayTy = CS.createTypeVariable(locator, TVO_PrefersSubtypeBinding);
// The array must be an array literal type. // The array must be an array literal type.

View File

@@ -1093,6 +1093,7 @@ private:
Score CurrentScore; Score CurrentScore;
SmallVector<TypeVariableType *, 16> TypeVariables; SmallVector<TypeVariableType *, 16> TypeVariables;
llvm::DenseMap<Expr *, Type *> ContextualTypes;
llvm::DenseMap<UnresolvedDotExpr *, ApplyExpr *> PossibleDynamicLookupCalls; llvm::DenseMap<UnresolvedDotExpr *, ApplyExpr *> PossibleDynamicLookupCalls;
@@ -1315,6 +1316,14 @@ public:
return TypeVariables; return TypeVariables;
} }
Type* getContextualType(Expr *E) {
return this->ContextualTypes[E];
}
void setContextualType(Expr *E, Type *T) {
this->ContextualTypes[E] = T;
}
/// \brief Retrieve the constraint locator for the given anchor and /// \brief Retrieve the constraint locator for the given anchor and
/// path, uniqued. /// path, uniqued.
ConstraintLocator * ConstraintLocator *

View File

@@ -734,6 +734,7 @@ static void diagnoseExpr(TypeChecker &TC, const Expr *E,
bool TypeChecker::typeCheckExpression( bool TypeChecker::typeCheckExpression(
Expr *&expr, DeclContext *dc, Expr *&expr, DeclContext *dc,
Type convertType, Type convertType,
Type contextualType,
bool discardedExpr, bool discardedExpr,
FreeTypeVariableBinding allowFreeTypeVariables, FreeTypeVariableBinding allowFreeTypeVariables,
ExprTypeCheckListener *listener) { ExprTypeCheckListener *listener) {
@@ -746,6 +747,11 @@ bool TypeChecker::typeCheckExpression(
// Construct a constraint system from this expression. // Construct a constraint system from this expression.
ConstraintSystem cs(*this, dc, ConstraintSystemFlags::AllowFixes); ConstraintSystem cs(*this, dc, ConstraintSystemFlags::AllowFixes);
if (!contextualType.isNull()) {
cs.setContextualType(expr, &contextualType);
}
CleanupIllFormedExpressionRAII cleanup(cs, expr); CleanupIllFormedExpressionRAII cleanup(cs, expr);
if (auto generatedExpr = cs.generateConstraints(expr)) if (auto generatedExpr = cs.generateConstraints(expr))
expr = generatedExpr; expr = generatedExpr;
@@ -1028,8 +1034,13 @@ bool TypeChecker::typeCheckBinding(PatternBindingDecl *binding) {
DC = initContext; DC = initContext;
} }
auto contextualType = binding->getPattern()->hasType() ?
binding->getPattern()->getType() :
Type();
// Type-check the initializer. // Type-check the initializer.
bool hadError = typeCheckExpression(init, DC, Type(), /*discardedExpr=*/false, bool hadError = typeCheckExpression(init, DC, Type(),
contextualType, /*discardedExpr=*/false,
FreeTypeVariableBinding::Disallow, FreeTypeVariableBinding::Disallow,
&listener); &listener);
@@ -1167,7 +1178,7 @@ bool TypeChecker::typeCheckCondition(Expr *&expr, DeclContext *dc) {
}; };
ConditionListener listener; ConditionListener listener;
return typeCheckExpression(expr, dc, Type(), /*discardedExpr=*/false, return typeCheckExpression(expr, dc, Type(), Type(), /*discardedExpr=*/false,
FreeTypeVariableBinding::Disallow, FreeTypeVariableBinding::Disallow,
&listener); &listener);
} }
@@ -1255,7 +1266,7 @@ bool TypeChecker::typeCheckArrayBound(Expr *&expr, bool constantRequired,
}; };
ArrayBoundListener listener; ArrayBoundListener listener;
return typeCheckExpression(expr, dc, Type(), /*discardedExpr=*/false, return typeCheckExpression(expr, dc, Type(), Type(), /*discardedExpr=*/false,
FreeTypeVariableBinding::Disallow, &listener); FreeTypeVariableBinding::Disallow, &listener);
} }

View File

@@ -2680,7 +2680,7 @@ public:
} }
elt->setRawValueExpr(nextValue); elt->setRawValueExpr(nextValue);
Expr *typeChecked = nextValue; Expr *typeChecked = nextValue;
if (!TC.typeCheckExpression(typeChecked, ED, rawTy, false)) if (!TC.typeCheckExpression(typeChecked, ED, rawTy, Type(), false))
elt->setTypeCheckedRawValueExpr(typeChecked); elt->setTypeCheckedRawValueExpr(typeChecked);
} else { } else {
lastExplicitValueElt = elt; lastExplicitValueElt = elt;
@@ -4192,7 +4192,7 @@ public:
// Recover by setting the raw type as this element's type. // Recover by setting the raw type as this element's type.
} }
Expr *typeCheckedExpr = rawValue; Expr *typeCheckedExpr = rawValue;
if (!TC.typeCheckExpression(typeCheckedExpr, ED, rawTy, false)) if (!TC.typeCheckExpression(typeCheckedExpr, ED, rawTy, Type(), false))
EED->setTypeCheckedRawValueExpr(typeCheckedExpr); EED->setTypeCheckedRawValueExpr(typeCheckedExpr);
} }
} else if (EED->getRecursiveness() == } else if (EED->getRecursiveness() ==
@@ -5382,7 +5382,7 @@ void TypeChecker::addImplicitEnumConformances(EnumDecl *ED) {
assert(elt->hasRawValueExpr()); assert(elt->hasRawValueExpr());
Expr *typeChecked = elt->getRawValueExpr(); Expr *typeChecked = elt->getRawValueExpr();
Type rawTy = ArchetypeBuilder::mapTypeIntoContext(ED, ED->getRawType()); Type rawTy = ArchetypeBuilder::mapTypeIntoContext(ED, ED->getRawType());
bool error = typeCheckExpression(typeChecked, ED, rawTy, false); bool error = typeCheckExpression(typeChecked, ED, rawTy, Type(), false);
assert(!error); (void)error; assert(!error); (void)error;
elt->setTypeCheckedRawValueExpr(typeChecked); elt->setTypeCheckedRawValueExpr(typeChecked);
} }

View File

@@ -856,7 +856,7 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type,
Expr *init = initHandle->getExpr(); Expr *init = initHandle->getExpr();
if (initHandle->alreadyChecked()) { if (initHandle->alreadyChecked()) {
// Nothing to do // Nothing to do
} else if (typeCheckExpression(init, dc, CoercionType, } else if (typeCheckExpression(init, dc, CoercionType, Type(),
/*discardedExpr=*/false)) { /*discardedExpr=*/false)) {
initHandle->setExpr(initHandle->getExpr(), true); initHandle->setExpr(initHandle->getExpr(), true);
} else { } else {

View File

@@ -282,7 +282,7 @@ public:
} }
Expr *E = RS->getResult(); Expr *E = RS->getResult();
if (TC.typeCheckExpression(E, DC, ResultTy, /*discardedExpr=*/false)) if (TC.typeCheckExpression(E, DC, ResultTy, Type(), /*discardedExpr=*/false))
return 0; return 0;
RS->setResult(E); RS->setResult(E);
@@ -345,7 +345,8 @@ public:
TC.typeCheckDecl(D, /*isFirstPass*/false); TC.typeCheckDecl(D, /*isFirstPass*/false);
if (auto *Initializer = FS->getInitializer().getPtrOrNull()) { if (auto *Initializer = FS->getInitializer().getPtrOrNull()) {
if (TC.typeCheckExpression(Initializer, DC, Type(), /*discardedExpr=*/true)) if (TC.typeCheckExpression(Initializer, DC, Type(), Type(),
/*discardedExpr=*/true))
return 0; return 0;
FS->setInitializer(Initializer); FS->setInitializer(Initializer);
} }
@@ -357,7 +358,8 @@ public:
} }
if (auto *Increment = FS->getIncrement().getPtrOrNull()) { if (auto *Increment = FS->getIncrement().getPtrOrNull()) {
if (TC.typeCheckExpression(Increment, DC, Type(), /*discardedExpr=*/true)) if (TC.typeCheckExpression(Increment, DC, Type(), Type(),
/*discardedExpr=*/true))
return 0; return 0;
FS->setIncrement(Increment); FS->setIncrement(Increment);
} }
@@ -373,7 +375,8 @@ public:
Stmt *visitForEachStmt(ForEachStmt *S) { Stmt *visitForEachStmt(ForEachStmt *S) {
// Type-check the container and convert it to an rvalue. // Type-check the container and convert it to an rvalue.
Expr *Sequence = S->getSequence(); Expr *Sequence = S->getSequence();
if (TC.typeCheckExpression(Sequence, DC, Type(), /*discardedExpr=*/false)) if (TC.typeCheckExpression(Sequence, DC, Type(), Type(),
/*discardedExpr=*/false))
return nullptr; return nullptr;
S->setSequence(Sequence); S->setSequence(Sequence);
@@ -597,7 +600,7 @@ public:
Stmt *visitSwitchStmt(SwitchStmt *S) { Stmt *visitSwitchStmt(SwitchStmt *S) {
// Type-check the subject expression. // Type-check the subject expression.
Expr *subjectExpr = S->getSubjectExpr(); Expr *subjectExpr = S->getSubjectExpr();
if (TC.typeCheckExpression(subjectExpr, DC, Type(), if (TC.typeCheckExpression(subjectExpr, DC, Type(), Type(),
/*discardedExpr=*/false)) /*discardedExpr=*/false))
return nullptr; return nullptr;
subjectExpr = TC.coerceToMaterializable(subjectExpr); subjectExpr = TC.coerceToMaterializable(subjectExpr);
@@ -677,7 +680,7 @@ Stmt *StmtChecker::visitBraceStmt(BraceStmt *BS) {
// Type check the expression. // Type check the expression.
bool isDiscarded = !(IsREPL && isa<TopLevelCodeDecl>(DC)); bool isDiscarded = !(IsREPL && isa<TopLevelCodeDecl>(DC));
if (TC.typeCheckExpression(SubExpr, DC, Type(), isDiscarded)) { if (TC.typeCheckExpression(SubExpr, DC, Type(), Type(), isDiscarded)) {
elem = SubExpr; elem = SubExpr;
continue; continue;
} }
@@ -765,7 +768,7 @@ static void checkDefaultArguments(TypeChecker &tc, Pattern *pattern,
// Type-check the initializer, then flag that we did so. // Type-check the initializer, then flag that we did so.
if (tc.typeCheckExpression(e, initContext, if (tc.typeCheckExpression(e, initContext,
field.getPattern()->getType(), field.getPattern()->getType(), Type(),
/*discardedExpr=*/false)) /*discardedExpr=*/false))
field.getInit()->setExpr(field.getInit()->getExpr(), true); field.getInit()->setExpr(field.getInit()->getExpr(), true);
else else
@@ -868,7 +871,7 @@ Expr* TypeChecker::constructCallToSuperInit(ConstructorDecl *ctor,
virtual bool suppressDiagnostics() const { return true; } virtual bool suppressDiagnostics() const { return true; }
} listener; } listener;
if (!typeCheckExpression(r, ctor, Type(), /*discardedExpr=*/true, if (!typeCheckExpression(r, ctor, Type(), Type(), /*discardedExpr=*/true,
FreeTypeVariableBinding::Disallow, &listener)) FreeTypeVariableBinding::Disallow, &listener))
return r; return r;

View File

@@ -450,7 +450,7 @@ bool swift::typeCheckCompletionContextExpr(ASTContext &Ctx, DeclContext *DC,
DiagnosticEngine diags(Ctx.SourceMgr); DiagnosticEngine diags(Ctx.SourceMgr);
TypeChecker TC(Ctx, diags); TypeChecker TC(Ctx, diags);
TC.typeCheckExpression(parsedExpr, DC, Type(), /*discardedExpr=*/true, TC.typeCheckExpression(parsedExpr, DC, Type(), Type(), /*discardedExpr=*/true,
FreeTypeVariableBinding::GenericParameters); FreeTypeVariableBinding::GenericParameters);
return parsedExpr && !isa<ErrorExpr>(parsedExpr) return parsedExpr && !isa<ErrorExpr>(parsedExpr)

View File

@@ -622,7 +622,9 @@ public:
/// ///
/// \returns true if an error occurred, false otherwise. /// \returns true if an error occurred, false otherwise.
bool typeCheckExpression(Expr *&expr, DeclContext *dc, bool typeCheckExpression(Expr *&expr, DeclContext *dc,
Type convertType, bool discardedExpr, Type convertType,
Type contextualType,
bool discardedExpr,
FreeTypeVariableBinding allowFreeTypeVariables FreeTypeVariableBinding allowFreeTypeVariables
= FreeTypeVariableBinding::Disallow, = FreeTypeVariableBinding::Disallow,
ExprTypeCheckListener *listener = nullptr); ExprTypeCheckListener *listener = nullptr);

View File

@@ -131,3 +131,14 @@ let runceArray: Runcible[] = [Spoon(x: 219)]
// CHECK-NEXT: x: 219 // CHECK-NEXT: x: 219
dump(runceArray) dump(runceArray)
// type check a large array literal in a reasonable amount of time
let afd: Float[] = [
0.5, -0.5, -0.5, 1.0, 0.0, 0.0,
0.5, 0.5, -0.5, 1.0, 0.0, 0.0,
0.5, -0.5, 0.5, 1.0, 0.0, 0.0,
0.5, -0.5, 0.5, 1.0, 0.0, 0.0,
0.5, 0.5, -0.5, 1.0, 0.0, 0.0,
0.5, 0.5, 0.5, 1.0, 0.0, 0.0,
0.5, 0.5, -0.5, 0.0, 1.0, 0.0,
-0.5, 0.5, -0.5, 0.0, 1.0, 2.0
]