Skip to content
Closed
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 @@ -97,6 +97,8 @@ ERROR(expected_argument_in_contextual_member,none,
"member %0 expects argument of type %1", (DeclName, Type))
ERROR(expected_parens_in_contextual_member,none,
"member %0 is a function; did you mean to call it?", (DeclName))
ERROR(expected_parens_in_contextual_member_type,none,
"member %0 is a function that produces expected type %1; did you mean to call it?", (DeclName, Type))

ERROR(expected_result_in_contextual_member,none,
"member %0 in %2 produces result of type %1, but context expects %2",
Expand Down
23 changes: 16 additions & 7 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2703,17 +2703,16 @@ namespace {
}

Expr *visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) {
// Dig out the type of the base, which will be the result type of this
// expression. If constraint solving resolved this to an UnresolvedType,
// If constraint solving resolved the base type to an UnresolvedType,
// then we're in an ambiguity tolerant mode used for diagnostic
// generation. Just leave this as an unresolved member reference.
Type resultTy = simplifyType(cs.getType(expr));
if (resultTy->getRValueType()->is<UnresolvedType>()) {
cs.setType(expr, resultTy);
Type baseTy = simplifyType(solution.getUnresolvedMemberBaseType(expr));

if (baseTy->getRValueType()->is<UnresolvedType>()) {
cs.setType(expr, baseTy);
return expr;
}

Type baseTy = resultTy->getRValueType();
auto &ctx = cs.getASTContext();

// Find the selected member.
Expand Down Expand Up @@ -2771,7 +2770,8 @@ namespace {
diagnoseAmbiguousNominalMember(baseTy, result);
}

return coerceToType(result, resultTy, cs.getConstraintLocator(expr));
return coerceToType(result, simplifyType(cs.getType(expr)),
cs.getConstraintLocator(expr));
}

/// Diagnose if the base type is optional, we're referring to a nominal
Expand Down Expand Up @@ -8459,6 +8459,15 @@ void Solution::setExprTypes(Expr *expr) const {
expr->walk(SET);
}

Type Solution::getUnresolvedMemberBaseType(UnresolvedMemberExpr *expr) const {
auto result = unresolvedMemberBaseTypes.find(expr);
if (result != unresolvedMemberBaseTypes.end())
return result->second;

auto &cs = getConstraintSystem();
return cs.getUnresolvedMemberBaseType(expr);
}

/// MARK: SolutionResult implementation.

SolutionResult SolutionResult::forSolved(Solution &&solution) {
Expand Down
83 changes: 56 additions & 27 deletions lib/Sema/CSBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,20 @@ void ConstraintSystem::inferTransitiveSupertypeBindings(
return rhs->getAs<TypeVariableType>() == typeVar;
});

if (subtypeOf.empty())
llvm::SmallVector<Constraint *, 4> convertibleFrom;
if (!bindings.HasNonPreferredDefaultBindings)
llvm::copy_if(bindings.Sources, std::back_inserter(convertibleFrom),
[&](const Constraint *constraint) -> bool {
if (constraint->getKind() != ConstraintKind::Conversion &&
constraint->getKind()
!= ConstraintKind::ArgumentConversion)
return false;

auto rhs = simplifyType(constraint->getSecondType());
return rhs->getAs<TypeVariableType>() == typeVar;
});

if (convertibleFrom.empty() && subtypeOf.empty())
return;

// We need to make sure that there are no duplicate bindings in the
Expand All @@ -48,36 +61,47 @@ void ConstraintSystem::inferTransitiveSupertypeBindings(
for (const auto &binding : bindings.Bindings)
existingTypes.insert(binding.BindingType->getCanonicalType());

for (auto *constraint : subtypeOf) {
auto *tv =
simplifyType(constraint->getFirstType())->getAs<TypeVariableType>();
if (!tv)
continue;

auto relatedBindings = inferredBindings.find(tv);
if (relatedBindings == inferredBindings.end())
continue;
auto addTransitiveBindings = [&](llvm::SmallVector<Constraint *, 4> sources,
AllowedBindingKind additionalAllowedKind) {
for (auto *constraint : sources) {
auto *tv =
simplifyType(constraint->getFirstType())->getAs<TypeVariableType>();
if (!tv)
continue;

for (auto &binding : relatedBindings->getSecond().Bindings) {
// We need the binding kind for the potential binding to
// either be Exact or Supertypes in order for it to make sense
// to add Supertype bindings based on the relationship between
// our type variables.
if (binding.Kind != AllowedBindingKind::Exact &&
binding.Kind != AllowedBindingKind::Supertypes)
auto relatedBindings = inferredBindings.find(tv);
if (relatedBindings == inferredBindings.end())
continue;

auto type = binding.BindingType;
for (auto &binding : relatedBindings->getSecond().Bindings) {
// We need the binding kind for the potential binding to
// either be Exact or Supertypes in order for it to make sense
// to add Supertype bindings based on the relationship between
// our type variables.
if (binding.Kind != AllowedBindingKind::Exact &&
binding.Kind != additionalAllowedKind)
continue;

if (!existingTypes.insert(type->getCanonicalType()).second)
continue;
auto type = binding.BindingType;

if (ConstraintSystem::typeVarOccursInType(typeVar, type))
continue;
if (!existingTypes.insert(type->getCanonicalType()).second)
continue;

bindings.addPotentialBinding(
binding.withSameSource(type, AllowedBindingKind::Supertypes));
if (ConstraintSystem::typeVarOccursInType(typeVar, type))
continue;

bindings.addPotentialBinding(
binding.withSameSource(type, AllowedBindingKind::Supertypes));
}
}
};

if (!subtypeOf.empty()) {
addTransitiveBindings(subtypeOf, AllowedBindingKind::Supertypes);
}

if (!convertibleFrom.empty()) {
addTransitiveBindings(convertibleFrom, AllowedBindingKind::Subtypes);
}
}

Expand Down Expand Up @@ -202,6 +226,9 @@ void ConstraintSystem::PotentialBindings::addPotentialBinding(
if (binding.isDefaultableBinding())
++NumDefaultableBindings;

if (!binding.isPreferredDefaultBinding())
HasNonPreferredDefaultBindings = true;

Bindings.push_back(std::move(binding));
}

Expand Down Expand Up @@ -487,7 +514,8 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
case ConstraintKind::Conversion:
case ConstraintKind::ArgumentConversion:
case ConstraintKind::OperatorArgumentConversion:
case ConstraintKind::OptionalObject: {
case ConstraintKind::OptionalObject:
case ConstraintKind::PreferredDefault: {
// If there is a `bind param` constraint associated with
// current type variable, result should be aware of that
// fact. Binding set might be incomplete until
Expand Down Expand Up @@ -555,6 +583,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
case ConstraintKind::FunctionInput:
case ConstraintKind::FunctionResult:
case ConstraintKind::OpaqueUnderlyingType:
case ConstraintKind::NominalEqual:
// Constraints from which we can't do anything.
break;

Expand All @@ -575,15 +604,15 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
}

case ConstraintKind::Defaultable:
case ConstraintKind::DefaultClosureType:
case ConstraintKind::DefaultClosureType: {
// Do these in a separate pass.
if (getFixedTypeRecursive(constraint->getFirstType(), true)
->getAs<TypeVariableType>() == typeVar) {
defaultableConstraints.push_back(constraint);
hasNonDependentMemberRelationalConstraints = true;
}
break;

}
case ConstraintKind::Disjunction:
// FIXME: Recurse into these constraints to see whether this
// type variable is fully bound by any of them.
Expand Down
49 changes: 31 additions & 18 deletions lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1106,14 +1106,6 @@ bool MissingOptionalUnwrapFailure::diagnoseAsError() {

auto *anchor = castToExpr(getAnchor());

// If this is an unresolved member expr e.g. `.foo` its
// base type is going to be the same as result type minus
// r-value adjustment because base could be an l-value type.
// We want to fix both cases by only diagnose one of them,
// otherwise this is just going to result in a duplcate diagnostic.
if (getLocator()->isLastElement<LocatorPathElt::UnresolvedMember>())
return false;

if (auto assignExpr = dyn_cast<AssignExpr>(anchor))
anchor = assignExpr->getSrc();

Expand Down Expand Up @@ -2034,10 +2026,19 @@ bool ContextualFailure::diagnoseAsError() {
return false;
}

case ConstraintLocator::RValueAdjustment: {
case ConstraintLocator::UnresolvedMemberChainResult: {
auto &solution = getSolution();
auto overload = getOverloadChoiceIfAvailable(
getConstraintLocator(anchor, ConstraintLocator::UnresolvedMember));
auto member = anchor;
if (auto *CE = getAsExpr<CallExpr>(anchor))
member = CE->getFn();

auto kind = ConstraintLocator::Member;
if (isExpr<UnresolvedMemberExpr>(anchor))
kind = ConstraintLocator::UnresolvedMember;
else if (isExpr<SubscriptExpr>(anchor))
kind = ConstraintLocator::SubscriptMember;
auto overload = getOverloadChoiceIfAvailable(getConstraintLocator(member,
kind));
if (!(overload && overload->choice.isDecl()))
return false;

Expand Down Expand Up @@ -2072,13 +2073,22 @@ bool ContextualFailure::diagnoseAsError() {
});

if (numMissingArgs == 0 || numMissingArgs > 1) {
auto diagnostic = emitDiagnostic(
diag::expected_parens_in_contextual_member, choice->getName());

// If there are no parameters we can suggest a fix-it
// to form an explicit call.
if (numMissingArgs == 0)
diagnostic.fixItInsertAfter(getSourceRange().End, "()");
auto applyFixIt = [&](InFlightDiagnostic &diagnostic) {
// If there are no parameters we can suggest a fix-it
// to form an explicit call.
if (numMissingArgs == 0)
diagnostic.fixItInsertAfter(getSourceRange().End, "()");
};
if (fnType->getResult()->isEqual(toType)) {
auto diag = emitDiagnostic(
diag::expected_parens_in_contextual_member_type,
choice->getName(), fnType->getResult());
applyFixIt(diag);
} else {
auto diag = emitDiagnostic(diag::expected_parens_in_contextual_member,
choice->getName());
applyFixIt(diag);
}
} else {
emitDiagnostic(diag::expected_argument_in_contextual_member,
choice->getName(), params.front().getPlainType());
Expand Down Expand Up @@ -2296,6 +2306,9 @@ bool ContextualFailure::diagnoseMissingFunctionCall() const {
if (getLocator()->isLastElement<LocatorPathElt::RValueAdjustment>())
return false;

if (getLocator()->isLastElement<LocatorPathElt::UnresolvedMember>())
return false;

auto *srcFT = getFromType()->getAs<FunctionType>();
if (!srcFT ||
!(srcFT->getParams().empty() ||
Expand Down
Loading