mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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:
@@ -2177,7 +2177,8 @@ namespace {
|
||||
SourceLoc(), /*implicit*/ true);
|
||||
Expr *metaty = TypeExpr::createImplicit(baseElementType, tc.Context);
|
||||
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");
|
||||
|
||||
expr->setConstructionFunction(applyExpr);
|
||||
@@ -2870,7 +2871,7 @@ static Expr *getCallerDefaultArg(TypeChecker &tc, DeclContext *dc,
|
||||
// literal expression.
|
||||
Expr *init = new (tc.Context) MagicIdentifierLiteralExpr(magicKind, loc,
|
||||
/*Implicit=*/true);
|
||||
bool invalid = tc.typeCheckExpression(init, dc, defArg.second,
|
||||
bool invalid = tc.typeCheckExpression(init, dc, defArg.second, Type(),
|
||||
/*discardedExpr=*/false);
|
||||
assert(!invalid && "conversion cannot fail");
|
||||
(void)invalid;
|
||||
|
||||
@@ -542,6 +542,34 @@ namespace {
|
||||
C.getIdentifier("Element")).front());
|
||||
|
||||
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);
|
||||
|
||||
// The array must be an array literal type.
|
||||
|
||||
@@ -1093,6 +1093,7 @@ private:
|
||||
Score CurrentScore;
|
||||
|
||||
SmallVector<TypeVariableType *, 16> TypeVariables;
|
||||
llvm::DenseMap<Expr *, Type *> ContextualTypes;
|
||||
|
||||
llvm::DenseMap<UnresolvedDotExpr *, ApplyExpr *> PossibleDynamicLookupCalls;
|
||||
|
||||
@@ -1315,6 +1316,14 @@ public:
|
||||
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
|
||||
/// path, uniqued.
|
||||
ConstraintLocator *
|
||||
|
||||
@@ -734,6 +734,7 @@ static void diagnoseExpr(TypeChecker &TC, const Expr *E,
|
||||
bool TypeChecker::typeCheckExpression(
|
||||
Expr *&expr, DeclContext *dc,
|
||||
Type convertType,
|
||||
Type contextualType,
|
||||
bool discardedExpr,
|
||||
FreeTypeVariableBinding allowFreeTypeVariables,
|
||||
ExprTypeCheckListener *listener) {
|
||||
@@ -746,6 +747,11 @@ bool TypeChecker::typeCheckExpression(
|
||||
|
||||
// Construct a constraint system from this expression.
|
||||
ConstraintSystem cs(*this, dc, ConstraintSystemFlags::AllowFixes);
|
||||
|
||||
if (!contextualType.isNull()) {
|
||||
cs.setContextualType(expr, &contextualType);
|
||||
}
|
||||
|
||||
CleanupIllFormedExpressionRAII cleanup(cs, expr);
|
||||
if (auto generatedExpr = cs.generateConstraints(expr))
|
||||
expr = generatedExpr;
|
||||
@@ -1028,8 +1034,13 @@ bool TypeChecker::typeCheckBinding(PatternBindingDecl *binding) {
|
||||
DC = initContext;
|
||||
}
|
||||
|
||||
auto contextualType = binding->getPattern()->hasType() ?
|
||||
binding->getPattern()->getType() :
|
||||
Type();
|
||||
|
||||
// Type-check the initializer.
|
||||
bool hadError = typeCheckExpression(init, DC, Type(), /*discardedExpr=*/false,
|
||||
bool hadError = typeCheckExpression(init, DC, Type(),
|
||||
contextualType, /*discardedExpr=*/false,
|
||||
FreeTypeVariableBinding::Disallow,
|
||||
&listener);
|
||||
|
||||
@@ -1167,7 +1178,7 @@ bool TypeChecker::typeCheckCondition(Expr *&expr, DeclContext *dc) {
|
||||
};
|
||||
|
||||
ConditionListener listener;
|
||||
return typeCheckExpression(expr, dc, Type(), /*discardedExpr=*/false,
|
||||
return typeCheckExpression(expr, dc, Type(), Type(), /*discardedExpr=*/false,
|
||||
FreeTypeVariableBinding::Disallow,
|
||||
&listener);
|
||||
}
|
||||
@@ -1255,7 +1266,7 @@ bool TypeChecker::typeCheckArrayBound(Expr *&expr, bool constantRequired,
|
||||
};
|
||||
|
||||
ArrayBoundListener listener;
|
||||
return typeCheckExpression(expr, dc, Type(), /*discardedExpr=*/false,
|
||||
return typeCheckExpression(expr, dc, Type(), Type(), /*discardedExpr=*/false,
|
||||
FreeTypeVariableBinding::Disallow, &listener);
|
||||
}
|
||||
|
||||
|
||||
@@ -2680,7 +2680,7 @@ public:
|
||||
}
|
||||
elt->setRawValueExpr(nextValue);
|
||||
Expr *typeChecked = nextValue;
|
||||
if (!TC.typeCheckExpression(typeChecked, ED, rawTy, false))
|
||||
if (!TC.typeCheckExpression(typeChecked, ED, rawTy, Type(), false))
|
||||
elt->setTypeCheckedRawValueExpr(typeChecked);
|
||||
} else {
|
||||
lastExplicitValueElt = elt;
|
||||
@@ -4192,7 +4192,7 @@ public:
|
||||
// Recover by setting the raw type as this element's type.
|
||||
}
|
||||
Expr *typeCheckedExpr = rawValue;
|
||||
if (!TC.typeCheckExpression(typeCheckedExpr, ED, rawTy, false))
|
||||
if (!TC.typeCheckExpression(typeCheckedExpr, ED, rawTy, Type(), false))
|
||||
EED->setTypeCheckedRawValueExpr(typeCheckedExpr);
|
||||
}
|
||||
} else if (EED->getRecursiveness() ==
|
||||
@@ -5382,7 +5382,7 @@ void TypeChecker::addImplicitEnumConformances(EnumDecl *ED) {
|
||||
assert(elt->hasRawValueExpr());
|
||||
Expr *typeChecked = elt->getRawValueExpr();
|
||||
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;
|
||||
elt->setTypeCheckedRawValueExpr(typeChecked);
|
||||
}
|
||||
|
||||
@@ -856,7 +856,7 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type,
|
||||
Expr *init = initHandle->getExpr();
|
||||
if (initHandle->alreadyChecked()) {
|
||||
// Nothing to do
|
||||
} else if (typeCheckExpression(init, dc, CoercionType,
|
||||
} else if (typeCheckExpression(init, dc, CoercionType, Type(),
|
||||
/*discardedExpr=*/false)) {
|
||||
initHandle->setExpr(initHandle->getExpr(), true);
|
||||
} else {
|
||||
|
||||
@@ -282,7 +282,7 @@ public:
|
||||
}
|
||||
|
||||
Expr *E = RS->getResult();
|
||||
if (TC.typeCheckExpression(E, DC, ResultTy, /*discardedExpr=*/false))
|
||||
if (TC.typeCheckExpression(E, DC, ResultTy, Type(), /*discardedExpr=*/false))
|
||||
return 0;
|
||||
RS->setResult(E);
|
||||
|
||||
@@ -345,7 +345,8 @@ public:
|
||||
TC.typeCheckDecl(D, /*isFirstPass*/false);
|
||||
|
||||
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;
|
||||
FS->setInitializer(Initializer);
|
||||
}
|
||||
@@ -357,7 +358,8 @@ public:
|
||||
}
|
||||
|
||||
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;
|
||||
FS->setIncrement(Increment);
|
||||
}
|
||||
@@ -373,7 +375,8 @@ public:
|
||||
Stmt *visitForEachStmt(ForEachStmt *S) {
|
||||
// Type-check the container and convert it to an rvalue.
|
||||
Expr *Sequence = S->getSequence();
|
||||
if (TC.typeCheckExpression(Sequence, DC, Type(), /*discardedExpr=*/false))
|
||||
if (TC.typeCheckExpression(Sequence, DC, Type(), Type(),
|
||||
/*discardedExpr=*/false))
|
||||
return nullptr;
|
||||
S->setSequence(Sequence);
|
||||
|
||||
@@ -597,7 +600,7 @@ public:
|
||||
Stmt *visitSwitchStmt(SwitchStmt *S) {
|
||||
// Type-check the subject expression.
|
||||
Expr *subjectExpr = S->getSubjectExpr();
|
||||
if (TC.typeCheckExpression(subjectExpr, DC, Type(),
|
||||
if (TC.typeCheckExpression(subjectExpr, DC, Type(), Type(),
|
||||
/*discardedExpr=*/false))
|
||||
return nullptr;
|
||||
subjectExpr = TC.coerceToMaterializable(subjectExpr);
|
||||
@@ -677,7 +680,7 @@ Stmt *StmtChecker::visitBraceStmt(BraceStmt *BS) {
|
||||
|
||||
// Type check the expression.
|
||||
bool isDiscarded = !(IsREPL && isa<TopLevelCodeDecl>(DC));
|
||||
if (TC.typeCheckExpression(SubExpr, DC, Type(), isDiscarded)) {
|
||||
if (TC.typeCheckExpression(SubExpr, DC, Type(), Type(), isDiscarded)) {
|
||||
elem = SubExpr;
|
||||
continue;
|
||||
}
|
||||
@@ -765,7 +768,7 @@ static void checkDefaultArguments(TypeChecker &tc, Pattern *pattern,
|
||||
|
||||
// Type-check the initializer, then flag that we did so.
|
||||
if (tc.typeCheckExpression(e, initContext,
|
||||
field.getPattern()->getType(),
|
||||
field.getPattern()->getType(), Type(),
|
||||
/*discardedExpr=*/false))
|
||||
field.getInit()->setExpr(field.getInit()->getExpr(), true);
|
||||
else
|
||||
@@ -868,7 +871,7 @@ Expr* TypeChecker::constructCallToSuperInit(ConstructorDecl *ctor,
|
||||
virtual bool suppressDiagnostics() const { return true; }
|
||||
} listener;
|
||||
|
||||
if (!typeCheckExpression(r, ctor, Type(), /*discardedExpr=*/true,
|
||||
if (!typeCheckExpression(r, ctor, Type(), Type(), /*discardedExpr=*/true,
|
||||
FreeTypeVariableBinding::Disallow, &listener))
|
||||
return r;
|
||||
|
||||
|
||||
@@ -450,7 +450,7 @@ bool swift::typeCheckCompletionContextExpr(ASTContext &Ctx, DeclContext *DC,
|
||||
DiagnosticEngine diags(Ctx.SourceMgr);
|
||||
|
||||
TypeChecker TC(Ctx, diags);
|
||||
TC.typeCheckExpression(parsedExpr, DC, Type(), /*discardedExpr=*/true,
|
||||
TC.typeCheckExpression(parsedExpr, DC, Type(), Type(), /*discardedExpr=*/true,
|
||||
FreeTypeVariableBinding::GenericParameters);
|
||||
|
||||
return parsedExpr && !isa<ErrorExpr>(parsedExpr)
|
||||
|
||||
@@ -622,7 +622,9 @@ public:
|
||||
///
|
||||
/// \returns true if an error occurred, false otherwise.
|
||||
bool typeCheckExpression(Expr *&expr, DeclContext *dc,
|
||||
Type convertType, bool discardedExpr,
|
||||
Type convertType,
|
||||
Type contextualType,
|
||||
bool discardedExpr,
|
||||
FreeTypeVariableBinding allowFreeTypeVariables
|
||||
= FreeTypeVariableBinding::Disallow,
|
||||
ExprTypeCheckListener *listener = nullptr);
|
||||
|
||||
@@ -131,3 +131,14 @@ let runceArray: Runcible[] = [Spoon(x: 219)]
|
||||
// CHECK-NEXT: x: 219
|
||||
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
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user