Skip to content

CSGen: Infer generic arguments in typed placeholders #33680

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 33 additions & 51 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1328,17 +1328,11 @@ namespace {

Type
resolveTypeReferenceInExpression(TypeRepr *repr, TypeResolverContext resCtx,
OpenUnboundGenericTypeFn unboundTyOpener) {
if (!unboundTyOpener) {
unboundTyOpener = [](auto unboundTy) {
// FIXME: Don't let unbound generic types escape type resolution.
// For now, just return the unbound generic type.
return unboundTy;
};
}
const auto result =
TypeResolution::forContextual(CS.DC, resCtx, unboundTyOpener)
.resolveType(repr);
const ConstraintLocatorBuilder &locator) {
// Introduce type variables for unbound generics.
const auto opener = OpenUnboundGenericType(CS, locator);
const auto result = TypeResolution::forContextual(CS.DC, resCtx, opener)
.resolveType(repr);
if (result->hasError()) {
return Type();
}
Expand All @@ -1364,8 +1358,7 @@ namespace {
auto *repr = E->getTypeRepr();
assert(repr && "Explicit node has no type repr!");
type = resolveTypeReferenceInExpression(
repr, TypeResolverContext::InExpression,
OpenUnboundGenericType(CS, locator));
repr, TypeResolverContext::InExpression, locator);
}

if (!type || type->hasError()) return Type();
Expand Down Expand Up @@ -2067,10 +2060,8 @@ namespace {
const auto resolvedTy = resolveTypeReferenceInExpression(
closure->getExplicitResultTypeRepr(),
TypeResolverContext::InExpression,
// Introduce type variables for unbound generics.
OpenUnboundGenericType(
CS, CS.getConstraintLocator(
closure, ConstraintLocator::ClosureResult)));
CS.getConstraintLocator(closure,
ConstraintLocator::ClosureResult));
if (resolvedTy)
return resolvedTy;
}
Expand Down Expand Up @@ -2354,9 +2345,7 @@ namespace {

const Type castType = resolveTypeReferenceInExpression(
isPattern->getCastTypeRepr(), TypeResolverContext::InExpression,
OpenUnboundGenericType(CS,
locator.withPathElement(
LocatorPathElt::PatternMatch(pattern))));
locator.withPathElement(LocatorPathElt::PatternMatch(pattern)));
if (!castType) return Type();

auto *subPattern = isPattern->getSubPattern();
Expand Down Expand Up @@ -2407,32 +2396,31 @@ namespace {
FunctionRefKind functionRefKind = FunctionRefKind::Compound;
if (enumPattern->getParentType() || enumPattern->getParentTypeRepr()) {
// Resolve the parent type.
Type parentType = [&]() -> Type {
if (auto preTy = enumPattern->getParentType()) {
return preTy;
const auto parentType = [&] {
auto *const patternMatchLoc = CS.getConstraintLocator(
locator, {LocatorPathElt::PatternMatch(pattern),
ConstraintLocator::ParentType});

// FIXME: Sometimes the parent type is realized eagerly in
// ResolvePattern::visitUnresolvedDotExpr, so we have to open it
// ex post facto. Remove this once we learn how to resolve patterns
// while generating constraints to keep the opening of generic types
// contained within the type resolver.
if (const auto preresolvedTy = enumPattern->getParentType()) {
const auto openedTy =
CS.openUnboundGenericTypes(preresolvedTy, patternMatchLoc);
assert(openedTy);
return openedTy;
}

return resolveTypeReferenceInExpression(
enumPattern->getParentTypeRepr(),
TypeResolverContext::InExpression, [](auto unboundTy) {
// FIXME: We ought to pass an OpenUnboundGenericType object
// rather than calling CS.openUnboundGenericType below, but
// sometimes the parent type is resolved eagerly in
// ResolvePattern::visitUnresolvedDotExpr, letting unbound
// generics escape.
return unboundTy;
});
TypeResolverContext::InExpression, patternMatchLoc);
}();

if (!parentType)
return Type();

parentType = CS.openUnboundGenericTypes(
parentType, CS.getConstraintLocator(
locator, {LocatorPathElt::PatternMatch(pattern),
ConstraintLocator::ParentType}));

assert(parentType);

// Perform member lookup into the parent's metatype.
Type parentMetaType = MetatypeType::get(parentType);
CS.addValueMemberConstraint(
Expand Down Expand Up @@ -2976,8 +2964,7 @@ namespace {
// Validate the resulting type.
const auto toType = resolveTypeReferenceInExpression(
repr, TypeResolverContext::ExplicitCastExpr,
// Introduce type variables for unbound generics.
OpenUnboundGenericType(CS, CS.getConstraintLocator(expr)));
CS.getConstraintLocator(expr));
if (!toType)
return nullptr;

Expand All @@ -3003,8 +2990,7 @@ namespace {
auto *const repr = expr->getCastTypeRepr();
const auto toType = resolveTypeReferenceInExpression(
repr, TypeResolverContext::ExplicitCastExpr,
// Introduce type variables for unbound generics.
OpenUnboundGenericType(CS, CS.getConstraintLocator(expr)));
CS.getConstraintLocator(expr));
if (!toType)
return nullptr;

Expand Down Expand Up @@ -3036,8 +3022,7 @@ namespace {
auto *const repr = expr->getCastTypeRepr();
const auto toType = resolveTypeReferenceInExpression(
repr, TypeResolverContext::ExplicitCastExpr,
// Introduce type variables for unbound generics.
OpenUnboundGenericType(CS, CS.getConstraintLocator(expr)));
CS.getConstraintLocator(expr));
if (!toType)
return nullptr;

Expand All @@ -3064,8 +3049,7 @@ namespace {
auto &ctx = CS.getASTContext();
const auto toType = resolveTypeReferenceInExpression(
expr->getCastTypeRepr(), TypeResolverContext::ExplicitCastExpr,
// Introduce type variables for unbound generics.
OpenUnboundGenericType(CS, CS.getConstraintLocator(expr)));
CS.getConstraintLocator(expr));
if (!toType)
return nullptr;

Expand Down Expand Up @@ -3273,9 +3257,9 @@ namespace {
Type visitEditorPlaceholderExpr(EditorPlaceholderExpr *E) {
if (auto *placeholderRepr = E->getPlaceholderTypeRepr()) {
// Just resolve the referenced type.
// FIXME: The type reference needs to be opened into context.
return resolveTypeReferenceInExpression(
placeholderRepr, TypeResolverContext::InExpression, nullptr);
placeholderRepr, TypeResolverContext::InExpression,
CS.getConstraintLocator(E));
}

auto locator = CS.getConstraintLocator(E);
Expand Down Expand Up @@ -3346,9 +3330,7 @@ namespace {
// If a root type was explicitly given, then resolve it now.
if (auto rootRepr = E->getRootType()) {
const auto rootObjectTy = resolveTypeReferenceInExpression(
rootRepr, TypeResolverContext::InExpression,
// Introduce type variables for unbound generics.
OpenUnboundGenericType(CS, locator));
rootRepr, TypeResolverContext::InExpression, locator);
if (!rootObjectTy || rootObjectTy->hasError())
return Type();

Expand Down
4 changes: 4 additions & 0 deletions test/Sema/editor_placeholders.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

func foo(_ x: Int) -> Int {}
func foo(_ x: Float) -> Float {}
func foo<T>(_ t: T) -> T {}

var v = foo(<#T##x: Float##Float#>) // expected-error {{editor placeholder}}
v = "" // expected-error {{cannot assign value of type 'String' to type 'Float'}}
Expand Down Expand Up @@ -36,3 +37,6 @@ func test_ambiguity_with_placeholders(pairs: [(rank: Int, count: Int)]) -> Bool
// expected-error@-1 {{editor placeholder in source file}}
// expected-error@-2 {{ambiguous use of 'subscript(_:)'}}
}

let unboundInPlaceholder1: Array<Never> = <#T##Array#> // expected-error{{editor placeholder in source file}}
let unboundInPlaceholder2: Array<Never> = foo(<#T##t: Array##Array<Never>#>) // expected-error{{editor placeholder in source file}}