Skip to content

[ConstraintSystem] Use an explicit generic argument constraint for UnresolvedSpecializeExpr. #66657

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
Jun 15, 2023
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
58 changes: 6 additions & 52 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1808,60 +1808,14 @@ namespace {
}

if (AnyMetatypeType *meta = baseTy->getAs<AnyMetatypeType>()) {
if (BoundGenericType *bgt
= meta->getInstanceType()->getAs<BoundGenericType>()) {
ArrayRef<Type> typeVars = bgt->getGenericArgs();
auto specializations = expr->getUnresolvedParams();

// If we have too many generic arguments, complain.
if (specializations.size() > typeVars.size()) {
de.diagnose(expr->getSubExpr()->getLoc(),
diag::type_parameter_count_mismatch,
bgt->getDecl()->getName(), typeVars.size(),
specializations.size(),
/*too many arguments*/ false,
/*isParameterPack?*/ false)
.highlight(
SourceRange(expr->getLAngleLoc(), expr->getRAngleLoc()));
de.diagnose(bgt->getDecl(), diag::kind_declname_declared_here,
DescriptiveDeclKind::GenericType,
bgt->getDecl()->getName());
return Type();
}

// Bind the specified generic arguments to the type variables in the
// open type.
auto *const locator = CS.getConstraintLocator(expr);
auto options =
TypeResolutionOptions(TypeResolverContext::InExpression);
for (size_t i = 0, e = specializations.size(); i < e; ++i) {
PackExpansionExpr *elementEnv = nullptr;
if (!PackElementEnvironments.empty()) {
options |= TypeResolutionFlags::AllowPackReferences;
elementEnv = PackElementEnvironments.back();
}

const auto result = TypeResolution::resolveContextualType(
specializations[i], CS.DC, options,
// Introduce type variables for unbound generics.
OpenUnboundGenericType(CS, locator),
HandlePlaceholderType(CS, locator),
OpenPackElementType(CS, locator, elementEnv));
if (result->hasError())
return Type();

CS.addConstraint(ConstraintKind::Bind, typeVars[i], result,
locator);
}

return baseTy;
} else {
de.diagnose(expr->getSubExpr()->getLoc(), diag::not_a_generic_type,
meta->getInstanceType());
de.diagnose(expr->getLAngleLoc(),
diag::while_parsing_as_left_angle_bracket);
auto *overloadLocator = CS.getConstraintLocator(expr->getSubExpr());
if (addSpecializationConstraint(overloadLocator,
meta->getInstanceType(),
expr->getUnresolvedParams())) {
return Type();
}

return baseTy;
}

// FIXME: If the base type is a type variable, constrain it to a metatype
Expand Down
55 changes: 44 additions & 11 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13493,18 +13493,32 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
if (simplifiedBoundType->isTypeVariableOrMember())
return formUnsolved();

// If the overload hasn't been resolved, we can't simplify this constraint.
auto overloadLocator = getCalleeLocator(getConstraintLocator(locator));
auto selectedOverload = findSelectedOverloadFor(overloadLocator);
if (!selectedOverload)
return formUnsolved();
ValueDecl *decl;
SmallVector<OpenedType, 2> openedTypes;
if (auto *bound = dyn_cast<TypeAliasType>(type1.getPointer())) {
decl = bound->getDecl();
for (auto argType : bound->getDirectGenericArgs()) {
auto *typeVar = argType->getAs<TypeVariableType>();
auto *genericParam = typeVar->getImpl().getGenericParameter();
openedTypes.push_back({genericParam, typeVar});
}
} else {
// If the overload hasn't been resolved, we can't simplify this constraint.
auto overloadLocator = getCalleeLocator(getConstraintLocator(locator));
auto selectedOverload = findSelectedOverloadFor(overloadLocator);
if (!selectedOverload)
return formUnsolved();

auto overloadChoice = selectedOverload->choice;
if (!overloadChoice.isDecl()) {
return SolutionKind::Error;
auto overloadChoice = selectedOverload->choice;
if (!overloadChoice.isDecl()) {
return SolutionKind::Error;
}

decl = overloadChoice.getDecl();
auto openedOverloadTypes = getOpenedTypes(overloadLocator);
openedTypes.append(openedOverloadTypes.begin(), openedOverloadTypes.end());
}

auto decl = overloadChoice.getDecl();
auto genericContext = decl->getAsGenericContext();
if (!genericContext)
return SolutionKind::Error;
Expand All @@ -13518,9 +13532,28 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
// Map the generic parameters we have over to their opened types.
SmallVector<Type, 2> openedGenericParams;
auto genericParamDepth = genericParams->getParams()[0]->getDepth();
for (const auto &openedType : getOpenedTypes(overloadLocator)) {
for (const auto &openedType : openedTypes) {
if (openedType.first->getDepth() == genericParamDepth) {
openedGenericParams.push_back(Type(openedType.second));
// A generic argument list containing pack references expects
// those packs to be wrapped in pack expansion types. If this
// opened type represents the generic argument for a parameter
// pack, wrap generate the appropriate shape constraints and
// add a pack expansion to the argument list.
if (openedType.first->isParameterPack()) {
auto patternType = openedType.second;
auto *shapeLoc = getConstraintLocator(
locator.withPathElement(ConstraintLocator::PackShape));
auto *shapeType = createTypeVariable(shapeLoc,
TVO_CanBindToPack |
TVO_CanBindToHole);
addConstraint(ConstraintKind::ShapeOf,
shapeType, patternType, shapeLoc);

auto *expansion = PackExpansionType::get(patternType, shapeType);
openedGenericParams.push_back(expansion);
} else {
openedGenericParams.push_back(Type(openedType.second));
}
}
}
assert(openedGenericParams.size() == genericParams->size());
Expand Down
18 changes: 16 additions & 2 deletions test/Macros/macro_expand_variadic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,32 @@

// RUN: %empty-directory(%t)
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/variadic_macros.swift -g -no-toolchain-stdlib-rpath
// RUN: %target-typecheck-verify-swift -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) -module-name MacroUser -DTEST_DIAGNOSTICS -swift-version 5
// RUN: %target-build-swift -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) %s -o %t/main -module-name MacroUser -swift-version 5
// RUN: %target-typecheck-verify-swift -disable-availability-checking -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) -module-name MacroUser -DTEST_DIAGNOSTICS -swift-version 5
// RUN: %target-build-swift -Xfrontend -disable-availability-checking -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) %s -o %t/main -module-name MacroUser -swift-version 5
// RUN: %target-codesign %t/main
// RUN: %target-run %t/main | %FileCheck %s

@freestanding(expression) macro print<each Value>(_ value: repeat each Value) = #externalMacro(module: "MacroDefinition", type: "PrintMacro")

@freestanding(expression) macro Print<each Value>(_ value: repeat each Value) = #externalMacro(module: "MacroDefinition", type: "PrintMacro")

struct Print<each Value> {
init() {}
}

func testAmbiguity() {
let _ = Print<Int>()
}

func testIt() {
// CHECK: hello
// CHECK: [1, 2, 3, 4, 5]
#print("hello", [1, 2, 3, 4, 5])

// CHECK: hello
// CHECK: [1, 2, 3, 4, 5]
#print<String, [Int]>("hello", [1, 2, 3, 4, 5])

// CHECK: world
#print("world")
}
Expand Down
40 changes: 13 additions & 27 deletions test/decl/typealias/generic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@

struct MyType<TyA, TyB> { // expected-note {{generic type 'MyType' declared here}}
// expected-note @-1 {{arguments to generic parameter 'TyB' ('S' and 'Int') are expected to be equal}}
// expected-note @-2 6 {{arguments to generic parameter 'TyA' ('Float' and 'Int') are expected to be equal}}
// expected-note @-3 2 {{arguments to generic parameter 'TyA' ('Float' and 'Double') are expected to be equal}}
// expected-note @-4 2 {{arguments to generic parameter 'TyB' ('Int' and 'Float') are expected to be equal}}
// expected-note @-5 2 {{arguments to generic parameter 'TyB' ('Double' and 'Float') are expected to be equal}}

var a : TyA, b : TyB
}

Expand Down Expand Up @@ -255,23 +252,13 @@ let _: ConcreteStruct.O<Int> = ConcreteStruct.O(123)
let _: ConcreteStruct.O<Int> = ConcreteStruct.O<Int>(123)

// Qualified lookup of generic typealiases nested inside generic contexts
//
// FIXME marks cases which still don't work correctly, and either produce a
// spurious diagnostic, or are actually invalid and do not diagnose.
//
// This occurs because the constraint solver does the wrong thing with an
// UnresolvedSpecializeExpr applied to a generic typealias.
//
// In the other cases, we manage to fold the UnresolvedSpecializeExpr in the
// precheckExpression() phase, which handles generic typealiases correctly.

do {
let x1 = GenericClass.TA<Float>(a: 4.0, b: 1) // FIXME
let x2 = GenericClass.TA<Float>(a: 1, b: 4.0) // FIXME
let x1 = GenericClass.TA<Float>(a: 4.0, b: 1)
let x2 = GenericClass.TA<Float>(a: 1, b: 4.0)

// FIXME: Should not diagnose
let _: MyType<Double, Float> = x1 // expected-error {{cannot assign value of type 'MyType<Float, Int>' to type 'MyType<Double, Float>'}}
let _: MyType<Int, Float> = x2 // expected-error {{cannot assign value of type 'MyType<Float, Double>' to type 'MyType<Int, Float>'}}
let _: MyType<Double, Float> = x1
let _: MyType<Int, Float> = x2
}

let _ = GenericClass<Int>.TA(a: 4.0, b: 1) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
Expand All @@ -284,12 +271,11 @@ let _: GenericClass.TA = GenericClass.TA(a: 4.0, b: 1)
let _: GenericClass.TA = GenericClass.TA(a: 1, b: 4.0)

do {
let x1: GenericClass.TA = GenericClass.TA<Float>(a: 4.0, b: 1) // FIXME
let x2: GenericClass.TA = GenericClass.TA<Float>(a: 1, b: 4.0) // FIXME
let x1: GenericClass.TA = GenericClass.TA<Float>(a: 4.0, b: 1)
let x2: GenericClass.TA = GenericClass.TA<Float>(a: 1, b: 4.0)

// FIXME: Should not diagnose
let _: MyType<Double, Float> = x1 // expected-error {{cannot assign value of type 'MyType<Float, Int>' to type 'MyType<Double, Float>'}}
let _: MyType<Int, Float> = x2 // expected-error {{cannot assign value of type 'MyType<Float, Double>' to type 'MyType<Int, Float>'}}
let _: MyType<Double, Float> = x1
let _: MyType<Int, Float> = x2
}

let _: GenericClass.TA = GenericClass<Int>.TA(a: 4.0, b: 1) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
Expand All @@ -301,8 +287,8 @@ let _: GenericClass.TA = GenericClass<Int>.TA<Float>(a: 1, b: 4.0)
let _: GenericClass<Int>.TA = GenericClass.TA(a: 4.0, b: 1) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
let _: GenericClass<Int>.TA = GenericClass.TA(a: 1, b: 4.0)

let _: GenericClass<Int>.TA = GenericClass.TA<Float>(a: 4.0, b: 1) // expected-error {{cannot assign value of type 'MyType<Float, Int>' to type 'MyType<Int, Int>'}}
let _: GenericClass<Int>.TA = GenericClass.TA<Float>(a: 1, b: 4.0) // expected-error {{cannot assign value of type 'MyType<Float, Double>' to type 'MyType<Int, Double>'}}
let _: GenericClass<Int>.TA = GenericClass.TA<Float>(a: 4.0, b: 1) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
let _: GenericClass<Int>.TA = GenericClass.TA<Float>(a: 1, b: 4.0)

let _: GenericClass<Int>.TA = GenericClass<Int>.TA(a: 4.0, b: 1) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
let _: GenericClass<Int>.TA = GenericClass<Int>.TA(a: 1, b: 4.0)
Expand All @@ -313,8 +299,8 @@ let _: GenericClass<Int>.TA = GenericClass<Int>.TA<Float>(a: 1, b: 4.0)
let _: GenericClass<Int>.TA<Float> = GenericClass.TA(a: 4.0, b: 1) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
let _: GenericClass<Int>.TA<Float> = GenericClass.TA(a: 1, b: 4.0)

let _: GenericClass<Int>.TA<Float> = GenericClass.TA<Float>(a: 4.0, b: 1) // expected-error {{cannot assign value of type 'MyType<Float, Float>' to type 'GenericClass<Int>.TA<Float>' (aka 'MyType<Int, Float>')}}
let _: GenericClass<Int>.TA<Float> = GenericClass.TA<Float>(a: 1, b: 4.0) // expected-error {{cannot assign value of type 'MyType<Float, Float>' to type 'GenericClass<Int>.TA<Float>' (aka 'MyType<Int, Float>')}}
let _: GenericClass<Int>.TA<Float> = GenericClass.TA<Float>(a: 4.0, b: 1) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
let _: GenericClass<Int>.TA<Float> = GenericClass.TA<Float>(a: 1, b: 4.0)

let _: GenericClass<Int>.TA<Float> = GenericClass<Int>.TA(a: 4.0, b: 1) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
let _: GenericClass<Int>.TA<Float> = GenericClass<Int>.TA(a: 1, b: 4.0)
Expand Down