Skip to content

Revert "[Sema] Add specialization constraints for func and variable types, then diagnose w/fixes." #75489

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 1 commit into from
Jul 26, 2024
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
2 changes: 2 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -4605,6 +4605,8 @@ NOTE(duplicated_key_declared_here, none,
// Generic specializations
ERROR(cannot_explicitly_specialize_generic_function,none,
"cannot explicitly specialize a generic function", ())
ERROR(not_a_generic_definition,none,
"cannot specialize a non-generic definition", ())
ERROR(not_a_generic_type,none,
"cannot specialize non-generic type %0", (Type))
ERROR(protocol_declares_unknown_primary_assoc_type,none,
Expand Down
32 changes: 1 addition & 31 deletions include/swift/Sema/CSFix.h
Original file line number Diff line number Diff line change
Expand Up @@ -462,12 +462,9 @@ enum class FixKind : uint8_t {
/// because its name doesn't appear in 'initializes' or 'accesses' attributes.
AllowInvalidMemberReferenceInInitAccessor,

/// Ignore an attempt to specialize a non-generic type.
/// Ignore an attempt to specialize non-generic type.
AllowConcreteTypeSpecialization,

/// Ignore an attempt to specialize a generic function.
AllowGenericFunctionSpecialization,

/// Ignore an out-of-place \c then statement.
IgnoreOutOfPlaceThenStmt,

Expand Down Expand Up @@ -3746,33 +3743,6 @@ class AllowConcreteTypeSpecialization final : public ConstraintFix {
}
};

class AllowGenericFunctionSpecialization final : public ConstraintFix {
ValueDecl *Decl;

AllowGenericFunctionSpecialization(ConstraintSystem &cs, ValueDecl *decl,
ConstraintLocator *locator)
: ConstraintFix(cs, FixKind::AllowConcreteTypeSpecialization, locator),
Decl(decl) {}

public:
std::string getName() const override {
return "allow generic function specialization";
}

bool diagnose(const Solution &solution, bool asNote = false) const override;

bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
return diagnose(*commonFixes.front().first);
}

static AllowGenericFunctionSpecialization *
create(ConstraintSystem &cs, ValueDecl *decl, ConstraintLocator *locator);

static bool classof(const ConstraintFix *fix) {
return fix->getKind() == FixKind::AllowGenericFunctionSpecialization;
}
};

class IgnoreOutOfPlaceThenStmt final : public ConstraintFix {
IgnoreOutOfPlaceThenStmt(ConstraintSystem &cs, ConstraintLocator *locator)
: ConstraintFix(cs, FixKind::IgnoreOutOfPlaceThenStmt, locator) {}
Expand Down
4 changes: 1 addition & 3 deletions lib/Parse/ParseType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1476,9 +1476,7 @@ static bool isGenericTypeDisambiguatingToken(Parser &P) {
auto &tok = P.Tok;
switch (tok.getKind()) {
default:
// If this is the end of the expr (wouldn't match parseExprSequenceElement),
// prefer generic type list over an illegal unary postfix '>' operator.
return P.isStartOfSwiftDecl() || P.isStartOfStmt(/*prefer expr=*/true);
return false;
case tok::r_paren:
case tok::r_square:
case tok::l_brace:
Expand Down
7 changes: 1 addition & 6 deletions lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9360,12 +9360,7 @@ bool InvalidMemberReferenceWithinInitAccessor::diagnoseAsError() {
}

bool ConcreteTypeSpecialization::diagnoseAsError() {
emitDiagnostic(diag::not_a_generic_type, resolveType(ConcreteType));
return true;
}

bool GenericFunctionSpecialization::diagnoseAsError() {
emitDiagnostic(diag::cannot_explicitly_specialize_generic_function);
emitDiagnostic(diag::not_a_generic_type, ConcreteType);
return true;
}

Expand Down
13 changes: 1 addition & 12 deletions lib/Sema/CSDiagnostics.h
Original file line number Diff line number Diff line change
Expand Up @@ -3132,18 +3132,7 @@ class ConcreteTypeSpecialization final : public FailureDiagnostic {
ConcreteTypeSpecialization(const Solution &solution, Type concreteTy,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator),
ConcreteType(concreteTy) {}

bool diagnoseAsError() override;
};

class GenericFunctionSpecialization final : public FailureDiagnostic {
ValueDecl *Decl;

public:
GenericFunctionSpecialization(const Solution &solution, ValueDecl *decl,
ConstraintLocator *locator)
: FailureDiagnostic(solution, locator), Decl(decl) {}
ConcreteType(resolveType(concreteTy)) {}

bool diagnoseAsError() override;
};
Expand Down
12 changes: 0 additions & 12 deletions lib/Sema/CSFix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2616,18 +2616,6 @@ AllowConcreteTypeSpecialization::create(ConstraintSystem &cs, Type concreteTy,
AllowConcreteTypeSpecialization(cs, concreteTy, locator);
}

bool AllowGenericFunctionSpecialization::diagnose(const Solution &solution,
bool asNote) const {
GenericFunctionSpecialization failure(solution, Decl, getLocator());
return failure.diagnose(asNote);
}

AllowGenericFunctionSpecialization *AllowGenericFunctionSpecialization::create(
ConstraintSystem &cs, ValueDecl *decl, ConstraintLocator *locator) {
return new (cs.getAllocator())
AllowGenericFunctionSpecialization(cs, decl, locator);
}

bool IgnoreOutOfPlaceThenStmt::diagnose(const Solution &solution,
bool asNote) const {
OutOfPlaceThenStmtFailure failure(solution, getLocator());
Expand Down
74 changes: 50 additions & 24 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1903,9 +1903,9 @@ namespace {
/// introduce them as an explicit generic arguments constraint.
///
/// \returns true if resolving any of the specialization types failed.
void addSpecializationConstraint(ConstraintLocator *locator, Type boundType,
SourceLoc lAngleLoc,
ArrayRef<TypeRepr *> specializationArgs) {
bool addSpecializationConstraint(
ConstraintLocator *locator, Type boundType,
ArrayRef<TypeRepr *> specializationArgs) {
// Resolve each type.
SmallVector<Type, 2> specializationArgTypes;
auto options =
Expand All @@ -1916,36 +1916,61 @@ namespace {
options |= TypeResolutionFlags::AllowPackReferences;
elementEnv = OuterExpansions.back();
}
auto result = TypeResolution::resolveContextualType(
const auto result = TypeResolution::resolveContextualType(
specializationArg, CurDC, options,
// Introduce type variables for unbound generics.
OpenUnboundGenericType(CS, locator),
HandlePlaceholderType(CS, locator),
OpenPackElementType(CS, locator, elementEnv));
if (result->hasError()) {
auto &ctxt = CS.getASTContext();
auto *repr = new (ctxt) PlaceholderTypeRepr(specializationArg->getLoc());
result = PlaceholderType::get(ctxt, repr);
ctxt.Diags.diagnose(lAngleLoc,
diag::while_parsing_as_left_angle_bracket);
}
if (result->hasError())
return true;

specializationArgTypes.push_back(result);
}

auto constraint = Constraint::create(
CS, ConstraintKind::ExplicitGenericArguments, boundType,
PackType::get(CS.getASTContext(), specializationArgTypes), locator);
CS.addUnsolvedConstraint(constraint);
CS.activateConstraint(constraint);
CS.addConstraint(
ConstraintKind::ExplicitGenericArguments, boundType,
PackType::get(CS.getASTContext(), specializationArgTypes),
locator);
return false;
}

Type visitUnresolvedSpecializeExpr(UnresolvedSpecializeExpr *expr) {
auto baseTy = CS.getType(expr->getSubExpr());
auto *overloadLocator = CS.getConstraintLocator(expr->getSubExpr());
addSpecializationConstraint(
overloadLocator, baseTy->getMetatypeInstanceType(),
expr->getLAngleLoc(), expr->getUnresolvedParams());
return baseTy;

if (baseTy->isTypeVariableOrMember()) {
return baseTy;
}

// We currently only support explicit specialization of generic types.
// FIXME: We could support explicit function specialization.
auto &de = CS.getASTContext().Diags;
if (baseTy->is<AnyFunctionType>()) {
de.diagnose(expr->getSubExpr()->getLoc(),
diag::cannot_explicitly_specialize_generic_function);
de.diagnose(expr->getLAngleLoc(),
diag::while_parsing_as_left_angle_bracket);
return Type();
}

if (AnyMetatypeType *meta = baseTy->getAs<AnyMetatypeType>()) {
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
// of a bound generic type.
de.diagnose(expr->getSubExpr()->getLoc(),
diag::not_a_generic_definition);
de.diagnose(expr->getLAngleLoc(),
diag::while_parsing_as_left_angle_bracket);
return Type();
}

Type visitSequenceExpr(SequenceExpr *expr) {
Expand Down Expand Up @@ -4055,9 +4080,10 @@ namespace {

// Add explicit generic arguments, if there were any.
if (expr->getGenericArgsRange().isValid()) {
addSpecializationConstraint(CS.getConstraintLocator(expr), macroRefType,
expr->getGenericArgsRange().Start,
expr->getGenericArgs());
if (addSpecializationConstraint(
CS.getConstraintLocator(expr), macroRefType,
expr->getGenericArgs()))
return Type();
}

// Form the applicable-function constraint. The result type
Expand Down
22 changes: 9 additions & 13 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13950,8 +13950,6 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(

// Bail out if we haven't selected an overload yet.
auto simplifiedBoundType = simplifyType(type1, flags);
if (simplifiedBoundType->isPlaceholder())
return SolutionKind::Solved;
if (simplifiedBoundType->isTypeVariableOrMember())
return formUnsolved();

Expand Down Expand Up @@ -14044,12 +14042,13 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
}
}

if (!decl->getAsGenericContext())
return SolutionKind::Error;

auto genericParams = getGenericParams(decl);
if (!decl->getAsGenericContext() || !genericParams) {
return recordFix(AllowConcreteTypeSpecialization::create(
*this, type1, getConstraintLocator(locator)))
? SolutionKind::Error
: SolutionKind::Solved;
if (!genericParams) {
// FIXME: Record an error here that we're ignoring the parameters.
return SolutionKind::Solved;
}

// Map the generic parameters we have over to their opened types.
Expand Down Expand Up @@ -14082,14 +14081,12 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
}
}

// FIXME: We could support explicit function specialization.
if (openedGenericParams.empty() ||
(isa<AbstractFunctionDecl>(decl) && !hasParameterPack)) {
if (openedGenericParams.empty()) {
if (!shouldAttemptFixes())
return SolutionKind::Error;

return recordFix(AllowGenericFunctionSpecialization::create(
*this, decl, getConstraintLocator(locator)))
return recordFix(AllowConcreteTypeSpecialization::create(
*this, type1, getConstraintLocator(locator)))
? SolutionKind::Error
: SolutionKind::Solved;
}
Expand Down Expand Up @@ -15220,7 +15217,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
case FixKind::AllowAssociatedValueMismatch:
case FixKind::GenericArgumentsMismatch:
case FixKind::AllowConcreteTypeSpecialization:
case FixKind::AllowGenericFunctionSpecialization:
case FixKind::IgnoreGenericSpecializationArityMismatch:
case FixKind::IgnoreKeyPathSubscriptIndexMismatch:
case FixKind::AllowMemberRefOnExistential: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func test() {

S<Int>(t: 42).test() // expected-error {{ambiguous use of 'init(t:)'}}

// FIXME(diagnostics): This should produce ambiguity diagnostic too
S<Int>.staticFn()
// expected-error@-1 {{ambiguous use of 'staticFn()'}}
// expected-error@-1 {{generic parameter 'T' could not be inferred}}
}
14 changes: 4 additions & 10 deletions test/Parse/enum_element_pattern_swift4.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,10 @@ enum E {

static func testE(e: E) {
switch e {
case A<UndefinedTy>(): // expected-error {{cannot find type 'UndefinedTy' in scope}}
case A<UndefinedTy>(): // expected-error {{cannot specialize a non-generic definition}}
// expected-note@-1 {{while parsing this '<' as a type parameter bracket}}
// expected-error@-2 {{cannot specialize non-generic type 'E'}}
// expected-error@-3 {{cannot call value of non-function type 'E'}}
break
case B<Int>(): // expected-error {{cannot specialize non-generic type 'E'}}
// expected-error@-1 {{cannot call value of non-function type 'E'}}
case B<Int>(): // expected-error {{cannot specialize a non-generic definition}} expected-note {{while parsing this '<' as a type parameter bracket}}
break
default:
break;
Expand All @@ -25,13 +22,10 @@ enum E {

func testE(e: E) {
switch e {
case E.A<UndefinedTy>(): // expected-error {{cannot find type 'UndefinedTy' in scope}}
case E.A<UndefinedTy>(): // expected-error {{cannot specialize a non-generic definition}}
// expected-note@-1 {{while parsing this '<' as a type parameter bracket}}
// expected-error@-2 {{cannot specialize non-generic type 'E'}}
// expected-error@-3 {{cannot call value of non-function type 'E'}}
break
case E.B<Int>(): // expected-error {{cannot specialize non-generic type 'E'}}
// expected-error@-1 {{cannot call value of non-function type 'E'}}
case E.B<Int>(): // expected-error {{cannot specialize a non-generic definition}} expected-note {{while parsing this '<' as a type parameter bracket}}
break
case .C(): // expected-error {{pattern with associated values does not match enum case 'C'}}
// expected-note@-1 {{remove associated values to make the pattern match}} {{10-12=}}
Expand Down
16 changes: 5 additions & 11 deletions test/Parse/generic_disambiguation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,15 @@ var a, b, c, d : Int
_ = a < b
_ = (a < b, c > d)
// Parses as generic because of lparen after '>'
(a < b, c > (d)) // expected-error{{cannot find type 'b' in scope}}
// expected-note@-1 2 {{while parsing this '<' as a type parameter bracket}}
// expected-error@-2 {{cannot specialize non-generic type 'Int'}}
// expected-error@-3 {{cannot call value of non-function type 'Int'}}
// expected-error@-4 {{cannot find type 'c' in scope}}
(a < b, c > (d)) // expected-error{{cannot specialize a non-generic definition}}
// expected-note@-1 {{while parsing this '<' as a type parameter bracket}}
// Parses as generic because of lparen after '>'
(a<b, c>(d)) // expected-error{{cannot find type 'b' in scope}}
// expected-note@-1 2 {{while parsing this '<' as a type parameter bracket}}
// expected-error@-2 {{cannot specialize non-generic type 'Int'}}
// expected-error@-3 {{cannot call value of non-function type 'Int'}}
// expected-error@-4 {{cannot find type 'c' in scope}}
(a<b, c>(d)) // expected-error{{cannot specialize a non-generic definition}}
// expected-note@-1 {{while parsing this '<' as a type parameter bracket}}
_ = a>(b)
_ = a > (b)

generic<Int>(0) // expected-error{{cannot explicitly specialize a generic function}}
generic<Int>(0) // expected-error{{cannot explicitly specialize a generic function}} expected-note{{while parsing this '<' as a type parameter bracket}}

A<B>.c()
A<A<B>>.c()
Expand Down
41 changes: 0 additions & 41 deletions test/Sema/generic-arg-list.swift

This file was deleted.