Skip to content

Commit 31db51d

Browse files
authored
Merge pull request #16250 from slavapestov/start-removing-shallow-type-checking
Start removing typeCheckExpressionShallow()
2 parents 4e8ae19 + 7c6fc5a commit 31db51d

14 files changed

+94
-98
lines changed

lib/Sema/CSApply.cpp

Lines changed: 79 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -131,17 +131,17 @@ void Solution::computeSubstitutions(
131131
/// \param diag The diagnostic to emit if the protocol definition doesn't
132132
/// have a requirement with the given name.
133133
///
134-
/// \returns The named witness, or nullptr if no witness could be found.
135-
template <typename DeclTy>
136-
static DeclTy *findNamedWitnessImpl(
134+
/// \returns The named witness, or an empty ConcreteDeclRef if no witness
135+
/// could be found.
136+
ConcreteDeclRef findNamedWitnessImpl(
137137
TypeChecker &tc, DeclContext *dc, Type type,
138138
ProtocolDecl *proto, DeclName name,
139139
Diag<> diag,
140140
Optional<ProtocolConformanceRef> conformance = None) {
141141
// Find the named requirement.
142-
DeclTy *requirement = nullptr;
142+
ValueDecl *requirement = nullptr;
143143
for (auto member : proto->getMembers()) {
144-
auto d = dyn_cast<DeclTy>(member);
144+
auto d = dyn_cast<ValueDecl>(member);
145145
if (!d || !d->hasName())
146146
continue;
147147

@@ -159,7 +159,7 @@ static DeclTy *findNamedWitnessImpl(
159159
// Find the member used to satisfy the named requirement.
160160
if (!conformance) {
161161
conformance = tc.conformsToProtocol(type, proto, dc,
162-
ConformanceCheckFlags::InExpression);
162+
ConformanceCheckFlags::InExpression);
163163
if (!conformance)
164164
return nullptr;
165165
}
@@ -169,8 +169,7 @@ static DeclTy *findNamedWitnessImpl(
169169
if (!conformance->isConcrete())
170170
return requirement;
171171
auto concrete = conformance->getConcrete();
172-
// FIXME: Dropping substitutions here.
173-
return cast_or_null<DeclTy>(concrete->getWitnessDecl(requirement, &tc));
172+
return concrete->getWitnessDeclRef(requirement, &tc);
174173
}
175174

176175
static bool shouldAccessStorageDirectly(Expr *base, VarDecl *member,
@@ -2377,18 +2376,21 @@ namespace {
23772376
DeclName name(tc.Context, DeclBaseName::createConstructor(),
23782377
{ tc.Context.Id_stringInterpolation });
23792378
auto member
2380-
= findNamedWitnessImpl<ConstructorDecl>(
2379+
= findNamedWitnessImpl(
23812380
tc, dc, type,
23822381
interpolationProto, name,
23832382
diag::interpolation_broken_proto);
23842383

23852384
DeclName segmentName(tc.Context, DeclBaseName::createConstructor(),
23862385
{ tc.Context.Id_stringInterpolationSegment });
23872386
auto segmentMember
2388-
= findNamedWitnessImpl<ConstructorDecl>(
2387+
= findNamedWitnessImpl(
23892388
tc, dc, type, interpolationProto, segmentName,
23902389
diag::interpolation_broken_proto);
2391-
if (!member || !segmentMember)
2390+
if (!member ||
2391+
!segmentMember ||
2392+
!isa<ConstructorDecl>(member.getDecl()) ||
2393+
!isa<ConstructorDecl>(segmentMember.getDecl()))
23922394
return nullptr;
23932395

23942396
// Build a reference to the init(stringInterpolation:) initializer.
@@ -2399,7 +2401,7 @@ namespace {
23992401
Expr *memberRef =
24002402
new (tc.Context) MemberRefExpr(typeRef,
24012403
expr->getStartLoc(),
2402-
member,
2404+
member.getDecl(),
24032405
DeclNameLoc(expr->getStartLoc()),
24042406
/*Implicit=*/true);
24052407
cs.cacheSubExprTypes(memberRef);
@@ -3298,11 +3300,7 @@ namespace {
32983300
auto cond
32993301
= solution.convertBooleanTypeToBuiltinI1(expr->getCondExpr(),
33003302
cs.getConstraintLocator(expr));
3301-
if (!cond) {
3302-
cs.setType(expr->getCondExpr(), ErrorType::get(resultTy));
3303-
} else {
3304-
expr->setCondExpr(cond);
3305-
}
3303+
expr->setCondExpr(cond);
33063304

33073305
// Coerce the then/else branches to the common type.
33083306
expr->setThenExpr(coerceToType(expr->getThenExpr(), resultTy,
@@ -7013,45 +7011,38 @@ static Type adjustSelfTypeForMember(Type baseTy, ValueDecl *member,
70137011
AccessSemantics semantics,
70147012
DeclContext *UseDC) {
70157013
auto baseObjectTy = baseTy->getWithoutSpecifierType();
7016-
if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
7014+
7015+
if (isa<ConstructorDecl>(member))
7016+
return baseObjectTy;
7017+
7018+
if (auto func = dyn_cast<FuncDecl>(member)) {
70177019
// If 'self' is an inout type, turn the base type into an lvalue
70187020
// type with the same qualifiers.
7019-
auto selfParam = func->getInterfaceType()->getAs<AnyFunctionType>()->getParams();
7020-
assert(selfParam.size() == 1 && "found invalid arity of self param");
7021-
if (selfParam[0].getParameterFlags().isInOut()) {
7022-
// Unless we're looking at a nonmutating existential member. In which
7023-
// case, the member will be modeled as an inout but ExistentialMemberRef
7024-
// and ArchetypeMemberRef want to take the base as an rvalue.
7025-
if (auto *fd = dyn_cast<FuncDecl>(func))
7026-
if (!fd->isMutating() && baseObjectTy->is<ArchetypeType>())
7027-
return baseObjectTy;
7028-
7021+
if (func->isMutating())
70297022
return InOutType::get(baseObjectTy);
7030-
}
70317023

70327024
// Otherwise, return the rvalue type.
70337025
return baseObjectTy;
70347026
}
70357027

70367028
// If the base of the access is mutable, then we may be invoking a getter or
70377029
// setter that requires the base to be mutable.
7038-
if (auto *SD = dyn_cast<AbstractStorageDecl>(member)) {
7039-
bool isSettableFromHere = SD->isSettable(UseDC)
7040-
&& (!UseDC->getASTContext().LangOpts.EnableAccessControl
7041-
|| SD->isSetterAccessibleFrom(UseDC));
7042-
7043-
// If neither the property's getter nor its setter are mutating, the base
7044-
// can be an rvalue.
7045-
if (!SD->isGetterMutating()
7046-
&& (!isSettableFromHere || !SD->isSetterMutating()))
7047-
return baseObjectTy;
7048-
7049-
// If we're calling an accessor, keep the base as an inout type, because the
7050-
// getter may be mutating.
7051-
if (SD->hasAccessorFunctions() && baseTy->is<InOutType>() &&
7052-
semantics != AccessSemantics::DirectToStorage)
7053-
return InOutType::get(baseObjectTy);
7054-
}
7030+
auto *SD = cast<AbstractStorageDecl>(member);
7031+
bool isSettableFromHere = SD->isSettable(UseDC)
7032+
&& (!UseDC->getASTContext().LangOpts.EnableAccessControl
7033+
|| SD->isSetterAccessibleFrom(UseDC));
7034+
7035+
// If neither the property's getter nor its setter are mutating, the base
7036+
// can be an rvalue.
7037+
if (!SD->isGetterMutating()
7038+
&& (!isSettableFromHere || !SD->isSetterMutating()))
7039+
return baseObjectTy;
7040+
7041+
// If we're calling an accessor, keep the base as an inout type, because the
7042+
// getter may be mutating.
7043+
if (SD->hasAccessorFunctions() && baseTy->is<InOutType>() &&
7044+
semantics != AccessSemantics::DirectToStorage)
7045+
return InOutType::get(baseObjectTy);
70557046

70567047
// Accesses to non-function members in value types are done through an @lvalue
70577048
// type.
@@ -7287,11 +7278,11 @@ Expr *ExprRewriter::convertLiteralInPlace(Expr *literal,
72877278

72887279
// Find the witness that we'll use to initialize the type via a builtin
72897280
// literal.
7290-
auto witness = findNamedWitnessImpl<AbstractFunctionDecl>(
7281+
auto witness = findNamedWitnessImpl(
72917282
tc, dc, type->getRValueType(), builtinProtocol,
72927283
builtinLiteralFuncName, brokenBuiltinProtocolDiag,
72937284
*builtinConformance);
7294-
if (!witness)
7285+
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
72957286
return nullptr;
72967287

72977288
// Form a reference to the builtin conversion function.
@@ -7301,7 +7292,7 @@ Expr *ExprRewriter::convertLiteralInPlace(Expr *literal,
73017292

73027293
Expr *unresolvedDot = new (tc.Context) UnresolvedDotExpr(
73037294
base, SourceLoc(),
7304-
witness->getFullName(),
7295+
witness.getDecl()->getFullName(),
73057296
DeclNameLoc(base->getEndLoc()),
73067297
/*Implicit=*/true);
73077298
(void)tc.typeCheckExpression(unresolvedDot, dc);
@@ -7352,11 +7343,11 @@ Expr *ExprRewriter::convertLiteralInPlace(Expr *literal,
73527343
}
73537344

73547345
// Find the witness that we'll use to initialize the literal value.
7355-
auto witness = findNamedWitnessImpl<AbstractFunctionDecl>(
7346+
auto witness = findNamedWitnessImpl(
73567347
tc, dc, type->getRValueType(), protocol,
73577348
literalFuncName, brokenProtocolDiag,
73587349
conformance);
7359-
if (!witness)
7350+
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
73607351
return nullptr;
73617352

73627353
// Form a reference to the conversion function.
@@ -7366,7 +7357,7 @@ Expr *ExprRewriter::convertLiteralInPlace(Expr *literal,
73667357

73677358
Expr *unresolvedDot = new (tc.Context) UnresolvedDotExpr(
73687359
base, SourceLoc(),
7369-
witness->getFullName(),
7360+
witness.getDecl()->getFullName(),
73707361
DeclNameLoc(base->getEndLoc()),
73717362
/*Implicit=*/true);
73727363
(void)tc.typeCheckExpression(unresolvedDot, dc);
@@ -8367,18 +8358,20 @@ Expr *TypeChecker::callWitness(Expr *base, DeclContext *dc,
83678358
if (auto metaType = type->getAs<AnyMetatypeType>())
83688359
type = metaType->getInstanceType();
83698360

8370-
auto witness = findNamedWitnessImpl<AbstractFunctionDecl>(
8361+
auto witness = findNamedWitnessImpl(
83718362
*this, dc, type->getRValueType(), protocol,
83728363
name, brokenProtocolDiag);
8373-
if (!witness)
8364+
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
83748365
return nullptr;
83758366

8367+
auto *witnessFn = cast<AbstractFunctionDecl>(witness.getDecl());
8368+
83768369
// Form a syntactic expression that describes the reference to the
83778370
// witness.
83788371
// FIXME: Egregious hack.
83798372
auto unresolvedDot = new (Context) UnresolvedDotExpr(
83808373
base, SourceLoc(),
8381-
witness->getFullName(),
8374+
witness.getDecl()->getFullName(),
83828375
DeclNameLoc(base->getEndLoc()),
83838376
/*Implicit=*/true);
83848377
unresolvedDot->setFunctionRefKind(FunctionRefKind::SingleApply);
@@ -8387,7 +8380,7 @@ Expr *TypeChecker::callWitness(Expr *base, DeclContext *dc,
83878380
// Form a reference to the witness itself.
83888381
Type openedFullType, openedType;
83898382
std::tie(openedFullType, openedType)
8390-
= cs.getTypeOfMemberReference(base->getType(), witness, dc,
8383+
= cs.getTypeOfMemberReference(base->getType(), witness.getDecl(), dc,
83918384
/*isDynamicResult=*/false,
83928385
FunctionRefKind::DoubleApply,
83938386
dotLocator);
@@ -8400,9 +8393,9 @@ Expr *TypeChecker::callWitness(Expr *base, DeclContext *dc,
84008393
// FIXME: Standardize all callers to always provide all argument names,
84018394
// rather than hack around this.
84028395
CallExpr *call;
8403-
auto argLabels = witness->getFullName().getArgumentNames();
8396+
auto argLabels = witness.getDecl()->getFullName().getArgumentNames();
84048397
if (arguments.size() == 1 &&
8405-
(isVariadicWitness(witness) ||
8398+
(isVariadicWitness(witnessFn) ||
84068399
argumentNamesMatch(cs.getType(arguments[0]), argLabels))) {
84078400
call = CallExpr::create(Context, unresolvedDot, arguments[0], {}, {},
84088401
/*hasTrailingClosure=*/false,
@@ -8453,7 +8446,7 @@ Expr *TypeChecker::callWitness(Expr *base, DeclContext *dc,
84538446
/*suppressDiagnostics=*/false);
84548447

84558448
auto choice =
8456-
OverloadChoice(openedFullType, witness, FunctionRefKind::SingleApply);
8449+
OverloadChoice(openedFullType, witnessFn, FunctionRefKind::SingleApply);
84578450
auto memberRef = rewriter.buildMemberRef(
84588451
base, openedFullType, base->getStartLoc(), choice,
84598452
DeclNameLoc(base->getEndLoc()), openedType, dotLocator, dotLocator,
@@ -8502,45 +8495,48 @@ Solution::convertBooleanTypeToBuiltinI1(Expr *expr,
85028495
// Find the builtin method.
85038496
if (members.size() != 1) {
85048497
tc.diagnose(expr->getLoc(), diag::broken_bool);
8505-
return nullptr;
8498+
return expr;
85068499
}
85078500
auto *builtinMethod = dyn_cast<FuncDecl>(members[0].getValueDecl());
85088501
if (!builtinMethod) {
85098502
tc.diagnose(expr->getLoc(), diag::broken_bool);
8510-
return nullptr;
8503+
return expr;
85118504
}
85128505

8513-
// Form a reference to the builtin method.
8514-
Expr *memberRef = new (ctx) MemberRefExpr(expr, SourceLoc(),
8515-
builtinMethod,
8516-
DeclNameLoc(expr->getLoc()),
8517-
/*Implicit=*/true);
8518-
cs.cacheSubExprTypes(memberRef);
8519-
cs.setSubExprTypes(memberRef);
8520-
bool failed = tc.typeCheckExpressionShallow(memberRef, cs.DC);
8521-
cs.cacheExprTypes(memberRef);
8522-
assert(!failed && "Could not reference witness?");
8523-
(void)failed;
8506+
// The method is not generic, so there are no substitutions.
8507+
auto builtinMethodType = builtinMethod->getInterfaceType()
8508+
->castTo<FunctionType>();
8509+
8510+
// Form an unbound reference to the builtin method.
8511+
auto *declRef = new (ctx) DeclRefExpr(builtinMethod,
8512+
DeclNameLoc(expr->getLoc()),
8513+
/*Implicit=*/true);
8514+
declRef->setFunctionRefKind(FunctionRefKind::DoubleApply);
8515+
cs.setType(declRef, builtinMethodType);
85248516

8525-
// Call the builtin method.
85268517
auto getType = [&](const Expr *E) -> Type {
85278518
return cs.getType(E);
85288519
};
85298520

8530-
expr = CallExpr::createImplicit(ctx, memberRef, { }, { }, getType);
8531-
cs.cacheSubExprTypes(expr);
8532-
cs.setSubExprTypes(expr);
8533-
failed = tc.typeCheckExpressionShallow(expr, cs.DC);
8534-
cs.cacheExprTypes(expr);
8535-
assert(!failed && "Could not call witness?");
8536-
(void)failed;
8521+
// Apply 'self' to get the method value.
8522+
auto *methodRef = new (ctx) DotSyntaxCallExpr(declRef,
8523+
SourceLoc(),
8524+
expr);
8525+
cs.setType(methodRef, builtinMethodType->getResult());
8526+
8527+
// Apply the empty argument list to get the final result.
8528+
auto *result = CallExpr::createImplicit(ctx, methodRef,
8529+
{ }, { }, getType);
8530+
cs.setType(result, builtinMethodType->getResult()
8531+
->castTo<FunctionType>()->getResult());
8532+
cs.setType(result->getArg(), ctx.TheEmptyTupleType);
85378533

8538-
if (expr && !cs.getType(expr)->isBuiltinIntegerType(1)) {
8534+
if (!cs.getType(result)->isBuiltinIntegerType(1)) {
85398535
tc.diagnose(expr->getLoc(), diag::broken_bool);
8540-
return nullptr;
8536+
return result;
85418537
}
85428538

8543-
return expr;
8539+
return result;
85448540
}
85458541

85468542
Expr *Solution::convertOptionalToBool(Expr *expr,

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2613,7 +2613,7 @@ bool TypeChecker::typeCheckCondition(Expr *&expr, DeclContext *dc) {
26132613

26142614
// Convert the result to a Builtin.i1.
26152615
Expr *appliedSolution(constraints::Solution &solution,
2616-
Expr *expr) override {
2616+
Expr *expr) override {
26172617
auto &cs = solution.getConstraintSystem();
26182618

26192619
auto converted =

lib/Sema/TypeCheckREPL.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,9 @@ void REPLChecker::generatePrintOfExpression(StringRef NameStr, Expr *E) {
268268
CE->setBody(Body, false);
269269
TC.typeCheckClosureBody(CE);
270270

271-
Expr *TheCall = CallExpr::createImplicit(Context, CE, { E }, { });
272-
if (TC.typeCheckExpressionShallow(TheCall, Arg->getDeclContext()))
273-
return ;
271+
auto *TheCall = CallExpr::createImplicit(Context, CE, { E }, { });
272+
TheCall->getArg()->setType(ParenType::get(Context, E->getType()));
273+
TheCall->setType(Context.TheEmptyTupleType);
274274

275275
// Inject the call into the top level stream by wrapping it with a TLCD.
276276
auto *BS = BraceStmt::create(Context, Loc, ASTNode(TheCall),

test/NameBinding/scope_map_lookup.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift %s -enable-astscope-lookup
1+
// RUN: %target-typecheck-verify-swift -enable-astscope-lookup
22

33
// Name binding in default arguments
44

validation-test/compiler_crashers_2_fixed/0117-rdar33433087.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift %s
1+
// RUN: %target-typecheck-verify-swift
22

33
class C {
44
private init() {} // expected-note {{declared here}}

validation-test/compiler_crashers_2_fixed/0118-rdar31529413.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift %s
1+
// RUN: %target-typecheck-verify-swift
22

33
enum E { case A }
44

validation-test/compiler_crashers_2_fixed/0119-rdar33613329.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift %s
1+
// RUN: %target-typecheck-verify-swift
22

33
precedencegroup BindingPrecedence {
44
higherThan: DefaultPrecedence

validation-test/compiler_crashers_2_fixed/0146-rdar38309176.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift %s
1+
// RUN: %target-typecheck-verify-swift
22

33
func foo(_ msg: Int) {}
44
func foo(_ msg: Double) {}

validation-test/compiler_crashers_2_fixed/0147-rdar38505436.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: not %target-typecheck-verify-swift %s
1+
// RUN: not %target-typecheck-verify-swift
22

33
protocol P1 {
44
class N1 {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift %s
1+
// RUN: %target-typecheck-verify-swift
22

33
let b: () -> Void = withoutActuallyEscaping({ print("hello crash") }, do: { $0() })
44
// expected-error@-1 {{cannot convert value of type '()' to specified type '() -> Void'}}

validation-test/compiler_crashers_2_fixed/0149-rdar34852808.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift %s
1+
// RUN: %target-typecheck-verify-swift
22

33
func foo(optional: Int?) {
44
_ = { [value = optional ?? 0]

0 commit comments

Comments
 (0)