AST: Fix crash when attempting typo correction on class-bound archetype

Also clean up some of the badness here just a little bit.

Fixes <rdar://problem/31093620>.
This commit is contained in:
Slava Pestov
2017-03-20 13:27:11 -07:00
parent 95267109a3
commit 573e832f35
3 changed files with 62 additions and 11 deletions

View File

@@ -493,7 +493,7 @@ static void lookupVisibleMemberDeclsImpl(
VisitedSet &Visited) { VisitedSet &Visited) {
// Just look through l-valueness. It doesn't affect name lookup. // Just look through l-valueness. It doesn't affect name lookup.
assert(BaseTy && "lookup into null type"); assert(BaseTy && "lookup into null type");
BaseTy = BaseTy->getRValueType(); assert(!BaseTy->isLValueType());
// Handle metatype references, as in "some_type.some_member". These are // Handle metatype references, as in "some_type.some_member". These are
// special and can't have extensions. // special and can't have extensions.
@@ -674,7 +674,10 @@ public:
OverrideFilteringConsumer(Type BaseTy, const DeclContext *DC, OverrideFilteringConsumer(Type BaseTy, const DeclContext *DC,
LazyResolver *resolver) LazyResolver *resolver)
: BaseTy(BaseTy->getRValueType()), DC(DC), TypeResolver(resolver) { : BaseTy(BaseTy), DC(DC), TypeResolver(resolver) {
assert(!BaseTy->isLValueType());
if (auto *MetaTy = BaseTy->getAs<AnyMetatypeType>())
BaseTy = MetaTy->getInstanceType();
assert(DC && BaseTy); assert(DC && BaseTy);
} }
@@ -724,11 +727,24 @@ public:
} }
// Does it make sense to substitute types? // Does it make sense to substitute types?
bool shouldSubst = !BaseTy->hasUnboundGenericType() &&
!BaseTy->is<AnyMetatypeType>() && // Don't pass UnboundGenericType here. If you see this assertion
!BaseTy->isExistentialType() && // being hit, fix the caller, don't remove it.
!BaseTy->hasTypeVariable() && assert(!BaseTy->hasUnboundGenericType());
VD->getDeclContext()->isTypeContext();
// If the base type is AnyObject, we might be doing a dynamic
// lookup, so the base type won't match the type of the member's
// context type.
//
// If the base type is not a nominal type, we can't substitute
// the member type.
//
// If the member is a free function and not a member of a type,
// don't substitute either.
bool shouldSubst = (!BaseTy->isAnyObject() &&
!BaseTy->hasTypeVariable() &&
BaseTy->getNominalOrBoundGenericNominal() &&
VD->getDeclContext()->isTypeContext());
ModuleDecl *M = DC->getParentModule(); ModuleDecl *M = DC->getParentModule();
auto FoundSignature = VD->getOverloadSignature(); auto FoundSignature = VD->getOverloadSignature();
@@ -860,7 +876,7 @@ void swift::lookupVisibleDecls(VisibleDeclConsumer &Consumer,
if (ExtendedType) if (ExtendedType)
BaseDecl = ExtendedType->getNominalOrBoundGenericNominal(); BaseDecl = ExtendedType->getNominalOrBoundGenericNominal();
} else if (auto ND = dyn_cast<NominalTypeDecl>(DC)) { } else if (auto ND = dyn_cast<NominalTypeDecl>(DC)) {
ExtendedType = ND->getDeclaredType(); ExtendedType = ND->getDeclaredTypeInContext();
BaseDecl = ND; BaseDecl = ND;
} }

View File

@@ -3113,14 +3113,14 @@ public:
NeedLeadingDot = !HaveDot; NeedLeadingDot = !HaveDot;
// This is horrible // This is horrible
ExprType = ExprType->getRValueType();
this->ExprType = ExprType; this->ExprType = ExprType;
if (ExprType->hasTypeParameter()) { if (ExprType->hasTypeParameter()) {
DeclContext *DC; DeclContext *DC;
if (VD) { if (VD) {
DC = VD->getInnermostDeclContext(); DC = VD->getInnermostDeclContext();
this->ExprType = DC->mapTypeIntoContext(ExprType); this->ExprType = DC->mapTypeIntoContext(ExprType);
} else if (auto NTD = ExprType->getRValueType()->getRValueInstanceType() } else if (auto NTD = ExprType->getRValueInstanceType()->getAnyNominal()) {
->getAnyNominal()) {
DC = NTD; DC = NTD;
this->ExprType = DC->mapTypeIntoContext(ExprType); this->ExprType = DC->mapTypeIntoContext(ExprType);
} }
@@ -3138,7 +3138,7 @@ public:
Done = true; Done = true;
} }
} }
if (auto *TT = ExprType->getRValueType()->getAs<TupleType>()) { if (auto *TT = ExprType->getAs<TupleType>()) {
getTupleExprCompletions(TT); getTupleExprCompletions(TT);
Done = true; Done = true;
} }

View File

@@ -84,3 +84,38 @@ _ = [Any]().withUnsafeBufferPointer { (buf) -> [Any] in
guard let base = buf.baseAddress else { return [] } guard let base = buf.baseAddress else { return [] }
return (base ..< base + buf.count).m // expected-error {{value of type 'CountableRange<_>' has no member 'm'}} return (base ..< base + buf.count).m // expected-error {{value of type 'CountableRange<_>' has no member 'm'}}
} }
// Typo correction with class-bound archetypes.
class SomeClass {
func match1() {}
// expected-note@-1 {{did you mean 'match1'?}}
}
func takesSomeClassArchetype<T : SomeClass>(_ t: T) {
t.match0()
// expected-error@-1 {{value of type 'T' has no member 'match0'}}
}
// Typo correction of unqualified lookup from generic context.
struct Generic<T> {
func match1() {}
// expected-note@-1 {{did you mean 'match1'?}}
class Inner {
func doStuff() {
match0()
// expected-error@-1 {{use of unresolved identifier 'match0'}}
}
}
}
// Typo correction with AnyObject.
func takesAnyObject(_ t: AnyObject) {
_ = t.rawPointer
// expected-error@-1 {{value of type 'AnyObject' has no member 'rawPointer'}}
}
func takesAnyObjectArchetype<T : AnyObject>(_ t: T) {
_ = t.rawPointer
// expected-error@-1 {{value of type 'T' has no member 'rawPointer'}}
}