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);
|
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;
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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 *
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user