mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Macros] Add support for explicit generic arguments of macros.
Enable type checking support for explicitly specifying generic arguments to a macro, e.g., `#stringify<Double>(1 + 2)`. To do so, introduce a new kind of constraint that performs explicit argument matching against the generic parameters of a macro only after the overload is chosen.
This commit is contained in:
@@ -2306,6 +2306,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
|
||||
case ConstraintKind::BindTupleOfFunctionParams:
|
||||
case ConstraintKind::PackElementOf:
|
||||
case ConstraintKind::ShapeOf:
|
||||
case ConstraintKind::ExplicitGenericArguments:
|
||||
llvm_unreachable("Bad constraint kind in matchTupleTypes()");
|
||||
}
|
||||
|
||||
@@ -2666,6 +2667,7 @@ static bool matchFunctionRepresentations(FunctionType::ExtInfo einfo1,
|
||||
case ConstraintKind::BindTupleOfFunctionParams:
|
||||
case ConstraintKind::PackElementOf:
|
||||
case ConstraintKind::ShapeOf:
|
||||
case ConstraintKind::ExplicitGenericArguments:
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3084,6 +3086,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
|
||||
case ConstraintKind::BindTupleOfFunctionParams:
|
||||
case ConstraintKind::PackElementOf:
|
||||
case ConstraintKind::ShapeOf:
|
||||
case ConstraintKind::ExplicitGenericArguments:
|
||||
llvm_unreachable("Not a relational constraint");
|
||||
}
|
||||
|
||||
@@ -6459,6 +6462,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
|
||||
case ConstraintKind::BindTupleOfFunctionParams:
|
||||
case ConstraintKind::PackElementOf:
|
||||
case ConstraintKind::ShapeOf:
|
||||
case ConstraintKind::ExplicitGenericArguments:
|
||||
llvm_unreachable("Not a relational constraint");
|
||||
}
|
||||
}
|
||||
@@ -12644,6 +12648,95 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyShapeOfConstraint(
|
||||
return SolutionKind::Solved;
|
||||
}
|
||||
|
||||
ConstraintSystem::SolutionKind
|
||||
ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
|
||||
Type type1, Type type2, TypeMatchOptions flags,
|
||||
ConstraintLocatorBuilder locator) {
|
||||
auto formUnsolved = [&]() {
|
||||
// If we're supposed to generate constraints, do so.
|
||||
if (flags.contains(TMF_GenerateConstraints)) {
|
||||
auto *shapeOf = Constraint::create(
|
||||
*this, ConstraintKind::ShapeOf, type1, type2,
|
||||
getConstraintLocator(locator));
|
||||
|
||||
addUnsolvedConstraint(shapeOf);
|
||||
return SolutionKind::Solved;
|
||||
}
|
||||
|
||||
return SolutionKind::Unsolved;
|
||||
};
|
||||
|
||||
// Bail out if we haven't selected an overload yet.
|
||||
auto simplifiedBoundType = simplifyType(type1, flags);
|
||||
if (simplifiedBoundType->isTypeVariableOrMember())
|
||||
return formUnsolved();
|
||||
|
||||
// Determine the overload locator for this constraint.
|
||||
ConstraintLocator *overloadLocator = nullptr;
|
||||
if (auto anchorExpr = locator.getAnchor().dyn_cast<Expr *>()) {
|
||||
if (auto expansion = dyn_cast<MacroExpansionExpr>(anchorExpr)) {
|
||||
overloadLocator = getConstraintLocator(expansion);
|
||||
} else if (auto specialize =
|
||||
dyn_cast<UnresolvedSpecializeExpr>(anchorExpr)) {
|
||||
overloadLocator = getConstraintLocator(
|
||||
specialize->getSubExpr()->getSemanticsProvidingExpr());
|
||||
}
|
||||
} else if (auto anchorDecl = locator.getAnchor().dyn_cast<Decl *>()) {
|
||||
if (auto expansion = dyn_cast<MacroExpansionDecl>(anchorDecl)) {
|
||||
overloadLocator = getConstraintLocator(expansion);
|
||||
}
|
||||
}
|
||||
assert(overloadLocator && "Specialize expression has the wrong form");
|
||||
|
||||
// If the overload hasn't been resolved, we can't simplify this constraint.
|
||||
auto resolvedOverloadIter = getResolvedOverloads().find(overloadLocator);
|
||||
if (resolvedOverloadIter == getResolvedOverloads().end())
|
||||
return formUnsolved();
|
||||
|
||||
auto selectedOverload = resolvedOverloadIter->second;
|
||||
auto overloadChoice = selectedOverload.choice;
|
||||
if (!overloadChoice.isDecl()) {
|
||||
return SolutionKind::Error;
|
||||
}
|
||||
|
||||
auto decl = overloadChoice.getDecl();
|
||||
auto genericContext = decl->getAsGenericContext();
|
||||
if (!genericContext)
|
||||
return SolutionKind::Error;
|
||||
|
||||
auto genericParams = genericContext->getGenericParams();
|
||||
if (!genericParams || genericParams->size() == 0) {
|
||||
// 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.
|
||||
SmallVector<Type, 2> openedGenericParams;
|
||||
auto genericParamDepth = genericParams->getParams()[0]->getDepth();
|
||||
for (const auto &openedType : getOpenedTypes(overloadLocator)) {
|
||||
if (openedType.first->getDepth() == genericParamDepth) {
|
||||
openedGenericParams.push_back(Type(openedType.second));
|
||||
}
|
||||
}
|
||||
assert(openedGenericParams.size() == genericParams->size());
|
||||
|
||||
// Match the opened generic parameters to the specialized arguments.
|
||||
auto specializedArgs = type2->castTo<PackType>()->getElementTypes();
|
||||
PackMatcher matcher(openedGenericParams, specializedArgs, getASTContext());
|
||||
if (matcher.match())
|
||||
return SolutionKind::Error;
|
||||
|
||||
// Bind the opened generic parameters to the specialization arguments.
|
||||
for (const auto &pair : matcher.pairs) {
|
||||
addConstraint(
|
||||
ConstraintKind::Bind, pair.lhs, pair.rhs,
|
||||
getConstraintLocator(
|
||||
locator, LocatorPathElt::GenericArgument(pair.idx)));
|
||||
}
|
||||
|
||||
return SolutionKind::Solved;
|
||||
}
|
||||
|
||||
static llvm::PointerIntPair<Type, 3, unsigned>
|
||||
getBaseTypeForPointer(TypeBase *type) {
|
||||
unsigned unwrapCount = 0;
|
||||
@@ -13993,6 +14086,10 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
|
||||
case ConstraintKind::ShapeOf:
|
||||
return simplifyShapeOfConstraint(first, second, subflags, locator);
|
||||
|
||||
case ConstraintKind::ExplicitGenericArguments:
|
||||
return simplifyExplicitGenericArgumentsConstraint(
|
||||
first, second, subflags, locator);
|
||||
|
||||
case ConstraintKind::ValueMember:
|
||||
case ConstraintKind::UnresolvedValueMember:
|
||||
case ConstraintKind::ValueWitness:
|
||||
@@ -14583,6 +14680,11 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
|
||||
return simplifyShapeOfConstraint(
|
||||
constraint.getFirstType(), constraint.getSecondType(), /*flags*/ None,
|
||||
constraint.getLocator());
|
||||
|
||||
case ConstraintKind::ExplicitGenericArguments:
|
||||
return simplifyExplicitGenericArgumentsConstraint(
|
||||
constraint.getFirstType(), constraint.getSecondType(),
|
||||
/*flags*/ None, constraint.getLocator());
|
||||
}
|
||||
|
||||
llvm_unreachable("Unhandled ConstraintKind in switch.");
|
||||
|
||||
Reference in New Issue
Block a user