Skip to content

[CS] Restore a type variable for compatibility with rdar://85263844 #40224

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
Nov 18, 2021
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
4 changes: 4 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,10 @@ WARNING(coercion_may_fail_warning,none,
"coercion from %0 to %1 may fail; use 'as?' or 'as!' instead",
(Type, Type))

WARNING(tuple_label_mismatch_warning,none,
"tuple conversion from %0 to %1 mismatches labels",
(Type, Type))

ERROR(missing_explicit_conversion,none,
"%0 is not implicitly convertible to %1; "
"did you mean to use 'as' to explicitly convert?", (Type, Type))
Expand Down
24 changes: 24 additions & 0 deletions include/swift/Sema/CSFix.h
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,9 @@ enum class FixKind : uint8_t {
/// Ignore a type mismatch between deduced element type and externally
/// imposed one.
IgnoreCollectionElementContextualMismatch,

/// Produce a warning for a tuple label mismatch.
AllowTupleLabelMismatch,
};

class ConstraintFix {
Expand Down Expand Up @@ -2798,6 +2801,27 @@ class AllowInvalidStaticMemberRefOnProtocolMetatype final
}
};

/// Emit a warning for mismatched tuple labels.
class AllowTupleLabelMismatch final : public ContextualMismatch {
AllowTupleLabelMismatch(ConstraintSystem &cs, Type fromType, Type toType,
ConstraintLocator *locator)
: ContextualMismatch(cs, FixKind::AllowTupleLabelMismatch, fromType,
toType, locator, /*warning*/ true) {}

public:
std::string getName() const override { return "allow tuple label mismatch"; }

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

static AllowTupleLabelMismatch *create(ConstraintSystem &cs, Type fromType,
Type toType,
ConstraintLocator *locator);

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

class AllowNonOptionalWeak final : public ConstraintFix {
AllowNonOptionalWeak(ConstraintSystem &cs, ConstraintLocator *locator)
: ConstraintFix(cs, FixKind::AllowNonOptionalWeak, locator) {}
Expand Down
7 changes: 7 additions & 0 deletions include/swift/Sema/Constraint.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,12 @@ enum class ConstraintKind : char {
/// one type - type variable representing type of a node, other side is
/// the AST node to infer the type for.
ClosureBodyElement,
/// Do not add new uses of this, it only exists to retain compatibility for
/// rdar://85263844.
///
/// Binds the RHS type to a tuple of the params of a function typed LHS. Note
/// this discards function parameter flags.
BindTupleOfFunctionParams
};

/// Classification of the different kinds of constraints.
Expand Down Expand Up @@ -685,6 +691,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
case ConstraintKind::KeyPath:
case ConstraintKind::KeyPathApplication:
case ConstraintKind::Defaultable:
case ConstraintKind::BindTupleOfFunctionParams:
return ConstraintClassification::TypeProperty;

case ConstraintKind::Disjunction:
Expand Down
6 changes: 6 additions & 0 deletions include/swift/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -4748,6 +4748,12 @@ class ConstraintSystem {
TypeMatchOptions flags,
ConstraintLocatorBuilder locator);

/// Attempt to simplify a BindTupleOfFunctionParams constraint.
SolutionKind
simplifyBindTupleOfFunctionParamsConstraint(Type first, Type second,
TypeMatchOptions flags,
ConstraintLocatorBuilder locator);

/// Attempt to simplify the ApplicableFunction constraint.
SolutionKind simplifyApplicableFnConstraint(
Type type1, Type type2,
Expand Down
1 change: 1 addition & 0 deletions lib/Sema/CSBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1378,6 +1378,7 @@ void PotentialBindings::infer(Constraint *constraint) {
case ConstraintKind::KeyPath:
case ConstraintKind::ClosureBodyElement:
case ConstraintKind::Conjunction:
case ConstraintKind::BindTupleOfFunctionParams:
// Constraints from which we can't do anything.
break;

Expand Down
6 changes: 6 additions & 0 deletions lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7867,6 +7867,12 @@ bool InvalidWeakAttributeUse::diagnoseAsError() {
return true;
}

bool TupleLabelMismatchWarning::diagnoseAsError() {
emitDiagnostic(diag::tuple_label_mismatch_warning, getFromType(), getToType())
.highlight(getSourceRange());
return true;
}

bool SwiftToCPointerConversionInInvalidContext::diagnoseAsError() {
auto argInfo = getFunctionArgApplyInfo(getLocator());
if (!argInfo)
Expand Down
10 changes: 10 additions & 0 deletions lib/Sema/CSDiagnostics.h
Original file line number Diff line number Diff line change
Expand Up @@ -2620,6 +2620,16 @@ class InvalidWeakAttributeUse final : public FailureDiagnostic {
bool diagnoseAsError() override;
};

/// Emit a warning for mismatched tuple labels.
class TupleLabelMismatchWarning final : public ContextualFailure {
public:
TupleLabelMismatchWarning(const Solution &solution, Type fromType,
Type toType, ConstraintLocator *locator)
: ContextualFailure(solution, fromType, toType, locator) {}

bool diagnoseAsError() override;
};

/// Diagnose situations where Swift -> C pointer implicit conversion
/// is attempted on a Swift function instead of one imported from C header.
///
Expand Down
14 changes: 14 additions & 0 deletions lib/Sema/CSFix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2024,6 +2024,20 @@ AllowNonOptionalWeak *AllowNonOptionalWeak::create(ConstraintSystem &cs,
return new (cs.getAllocator()) AllowNonOptionalWeak(cs, locator);
}

AllowTupleLabelMismatch *
AllowTupleLabelMismatch::create(ConstraintSystem &cs, Type fromType,
Type toType, ConstraintLocator *locator) {
return new (cs.getAllocator())
AllowTupleLabelMismatch(cs, fromType, toType, locator);
}

bool AllowTupleLabelMismatch::diagnose(const Solution &solution,
bool asNote) const {
TupleLabelMismatchWarning warning(solution, getFromType(), getToType(),
getLocator());
return warning.diagnose(asNote);
}

bool AllowSwiftToCPointerConversion::diagnose(const Solution &solution,
bool asNote) const {
SwiftToCPointerConversionInInvalidContext failure(solution, getLocator());
Expand Down
13 changes: 13 additions & 0 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1525,6 +1525,19 @@ namespace {
auto methodTy =
CS.createTypeVariable(memberTypeLoc, TVO_CanBindToNoEscape);

// HACK: Bind the function's parameter list as a tuple to a type
// variable. This only exists to preserve compatibility with
// rdar://85263844, as it can affect the prioritization of bindings,
// which can affect behavior for tuple matching as tuple subtyping is
// currently a *weaker* constraint than tuple conversion.
if (!CS.getASTContext().isSwiftVersionAtLeast(6)) {
auto paramTypeVar = CS.createTypeVariable(
CS.getConstraintLocator(expr, ConstraintLocator::ApplyArgument),
TVO_CanBindToLValue | TVO_CanBindToInOut | TVO_CanBindToNoEscape);
CS.addConstraint(ConstraintKind::BindTupleOfFunctionParams, methodTy,
paramTypeVar, CS.getConstraintLocator(expr));
}

CS.addValueMemberConstraint(
baseTy, expr->getName(), methodTy, CurDC,
expr->getFunctionRefKind(),
Expand Down
93 changes: 93 additions & 0 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1620,6 +1620,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
}
}

auto hasLabelMismatch = false;
for (unsigned i = 0, n = tuple1->getNumElements(); i != n; ++i) {
const auto &elt1 = tuple1->getElement(i);
const auto &elt2 = tuple2->getElement(i);
Expand All @@ -1641,6 +1642,11 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
// used at some other position.
if (elt2.hasName() && tuple1->getNamedElementId(elt2.getName()) != -1)
return getTypeMatchFailure(locator);

// If both elements have names and they mismatch, make a note of it
// so we can emit a warning.
if (elt1.hasName() && elt2.hasName())
hasLabelMismatch = true;
}
}

Expand All @@ -1656,6 +1662,13 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
return result;
}

if (hasLabelMismatch) {
// If we had a label mismatch, emit a warning. This is something we
// shouldn't permit, as it's more permissive than what a conversion would
// allow. Ideally we'd turn this into an error in Swift 6 mode.
recordFix(AllowTupleLabelMismatch::create(
*this, tuple1, tuple2, getConstraintLocator(locator)));
}
return getTypeMatchSuccess();
}

Expand Down Expand Up @@ -1700,6 +1713,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
case ConstraintKind::UnresolvedMemberChainBase:
case ConstraintKind::PropertyWrapper:
case ConstraintKind::ClosureBodyElement:
case ConstraintKind::BindTupleOfFunctionParams:
llvm_unreachable("Not a conversion");
}

Expand Down Expand Up @@ -1839,6 +1853,7 @@ static bool matchFunctionRepresentations(FunctionType::ExtInfo einfo1,
case ConstraintKind::UnresolvedMemberChainBase:
case ConstraintKind::PropertyWrapper:
case ConstraintKind::ClosureBodyElement:
case ConstraintKind::BindTupleOfFunctionParams:
return true;
}

Expand Down Expand Up @@ -2250,6 +2265,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
case ConstraintKind::UnresolvedMemberChainBase:
case ConstraintKind::PropertyWrapper:
case ConstraintKind::ClosureBodyElement:
case ConstraintKind::BindTupleOfFunctionParams:
llvm_unreachable("Not a relational constraint");
}

Expand Down Expand Up @@ -5337,6 +5353,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
case ConstraintKind::UnresolvedMemberChainBase:
case ConstraintKind::PropertyWrapper:
case ConstraintKind::ClosureBodyElement:
case ConstraintKind::BindTupleOfFunctionParams:
llvm_unreachable("Not a relational constraint");
}
}
Expand Down Expand Up @@ -6308,6 +6325,19 @@ ConstraintSystem::simplifyConstructionConstraint(
fnLocator,
ConstraintLocator::ConstructorMember));

// HACK: Bind the function's parameter list as a tuple to a type variable.
// This only exists to preserve compatibility with rdar://85263844, as it can
// affect the prioritization of bindings, which can affect behavior for tuple
// matching as tuple subtyping is currently a *weaker* constraint than tuple
// conversion.
if (!getASTContext().isSwiftVersionAtLeast(6)) {
auto paramTypeVar = createTypeVariable(
getConstraintLocator(locator, ConstraintLocator::ApplyArgument),
TVO_CanBindToLValue | TVO_CanBindToInOut | TVO_CanBindToNoEscape);
addConstraint(ConstraintKind::BindTupleOfFunctionParams, memberType,
paramTypeVar, locator);
}

addConstraint(ConstraintKind::ApplicableFunction, fnType, memberType,
fnLocator);

Expand Down Expand Up @@ -7131,6 +7161,59 @@ ConstraintSystem::simplifyOptionalObjectConstraint(
return SolutionKind::Solved;
}

ConstraintSystem::SolutionKind
ConstraintSystem::simplifyBindTupleOfFunctionParamsConstraint(
Type first, Type second, TypeMatchOptions flags,
ConstraintLocatorBuilder locator) {
auto simplified = simplifyType(first);
auto simplifiedCopy = simplified;

unsigned unwrapCount = 0;
if (shouldAttemptFixes()) {
while (auto objectTy = simplified->getOptionalObjectType()) {
simplified = objectTy;

// Track how many times we do this so that we can record a fix for each.
++unwrapCount;
}

if (simplified->isPlaceholder()) {
if (auto *typeVar = second->getAs<TypeVariableType>())
recordPotentialHole(typeVar);
return SolutionKind::Solved;
}
}

if (simplified->isTypeVariableOrMember()) {
if (!flags.contains(TMF_GenerateConstraints))
return SolutionKind::Unsolved;

addUnsolvedConstraint(
Constraint::create(*this, ConstraintKind::BindTupleOfFunctionParams,
simplified, second, getConstraintLocator(locator)));
return SolutionKind::Solved;
}

auto *funcTy = simplified->getAs<FunctionType>();
if (!funcTy)
return SolutionKind::Error;

auto tupleTy =
AnyFunctionType::composeTuple(getASTContext(), funcTy->getParams(),
/*wantParamFlags*/ false);

addConstraint(ConstraintKind::Bind, tupleTy, second,
locator.withPathElement(ConstraintLocator::FunctionArgument));

if (unwrapCount > 0) {
auto *fix = ForceOptional::create(*this, simplifiedCopy, second,
getConstraintLocator(locator));
if (recordFix(fix, /*impact=*/unwrapCount))
return SolutionKind::Error;
}
return SolutionKind::Solved;
}

static bool isForKeyPathSubscript(ConstraintSystem &cs,
ConstraintLocator *locator) {
if (!locator || !locator->getAnchor())
Expand Down Expand Up @@ -11961,6 +12044,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
case FixKind::DropThrowsAttribute:
case FixKind::DropAsyncAttribute:
case FixKind::AllowSwiftToCPointerConversion:
case FixKind::AllowTupleLabelMismatch:
llvm_unreachable("handled elsewhere");
}

Expand Down Expand Up @@ -12046,6 +12130,10 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
return simplifyUnresolvedMemberChainBaseConstraint(first, second, subflags,
locator);

case ConstraintKind::BindTupleOfFunctionParams:
return simplifyBindTupleOfFunctionParamsConstraint(first, second, subflags,
locator);

case ConstraintKind::ValueMember:
case ConstraintKind::UnresolvedValueMember:
case ConstraintKind::ValueWitness:
Expand Down Expand Up @@ -12588,6 +12676,11 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
return simplifyClosureBodyElementConstraint(
constraint.getClosureElement(), constraint.getElementContext(),
/*flags=*/None, constraint.getLocator());

case ConstraintKind::BindTupleOfFunctionParams:
return simplifyBindTupleOfFunctionParamsConstraint(
constraint.getFirstType(), constraint.getSecondType(), /*flags*/ None,
constraint.getLocator());
}

llvm_unreachable("Unhandled ConstraintKind in switch.");
Expand Down
8 changes: 8 additions & 0 deletions lib/Sema/Constraint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second,
case ConstraintKind::OneWayBindParam:
case ConstraintKind::UnresolvedMemberChainBase:
case ConstraintKind::PropertyWrapper:
case ConstraintKind::BindTupleOfFunctionParams:
assert(!First.isNull());
assert(!Second.isNull());
break;
Expand Down Expand Up @@ -161,6 +162,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Type Third,
case ConstraintKind::UnresolvedMemberChainBase:
case ConstraintKind::PropertyWrapper:
case ConstraintKind::ClosureBodyElement:
case ConstraintKind::BindTupleOfFunctionParams:
llvm_unreachable("Wrong constructor");

case ConstraintKind::KeyPath:
Expand Down Expand Up @@ -303,6 +305,7 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const {
case ConstraintKind::DefaultClosureType:
case ConstraintKind::UnresolvedMemberChainBase:
case ConstraintKind::PropertyWrapper:
case ConstraintKind::BindTupleOfFunctionParams:
return create(cs, getKind(), getFirstType(), getSecondType(), getLocator());

case ConstraintKind::ApplicableFunction:
Expand Down Expand Up @@ -503,6 +506,10 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const {
Out << " can default to ";
break;

case ConstraintKind::BindTupleOfFunctionParams:
Out << " bind tuple of function params to ";
break;

case ConstraintKind::Disjunction:
llvm_unreachable("disjunction handled above");
case ConstraintKind::Conjunction:
Expand Down Expand Up @@ -663,6 +670,7 @@ gatherReferencedTypeVars(Constraint *constraint,
case ConstraintKind::DefaultClosureType:
case ConstraintKind::UnresolvedMemberChainBase:
case ConstraintKind::PropertyWrapper:
case ConstraintKind::BindTupleOfFunctionParams:
constraint->getFirstType()->getTypeVariables(typeVars);
constraint->getSecondType()->getTypeVariables(typeVars);
break;
Expand Down
Loading