Skip to content

Sema: Fix two bugs with type resolution of generic arguments [5.10] #69129

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
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
21 changes: 16 additions & 5 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -4373,10 +4373,21 @@ ERROR(cannot_specialize_self,none,
"cannot specialize 'Self'", ())
NOTE(specialize_explicit_type_instead,none,
"did you mean to explicitly reference %0 instead?", (Type))
ERROR(type_parameter_count_mismatch,none,
"generic type %0 specialized with %select{too many|too few}3 type "
"parameters (got %2, but expected %select{%1|at least %1}4)",
(Identifier, unsigned, unsigned, bool, bool))
ERROR(too_few_generic_arguments,none,
"generic type %0 specialized with too few type parameters "
"(got %1, but expected %2)",
(Identifier, unsigned, unsigned))
ERROR(too_few_generic_arguments_pack,none,
"generic type %0 specialized with too few type parameters "
"(got %1, but expected at least %2)",
(Identifier, unsigned, unsigned))
ERROR(too_many_generic_arguments,none,
"generic type %0 specialized with too many type parameters "
"(got %1, but expected %2)",
(Identifier, unsigned, unsigned))
ERROR(generic_argument_pack_mismatch,none,
"generic type %0 specialized with mismatched type parameter pack",
(Identifier))
ERROR(generic_type_requires_arguments,none,
"reference to generic type %0 requires arguments in <...>", (Type))
NOTE(descriptive_generic_type_declared_here,none,
Expand Down Expand Up @@ -5658,7 +5669,7 @@ ERROR(superclass_with_pack,none,
"cannot inherit from a generic class that declares a type pack", ())
ERROR(expansion_not_allowed,none,
"pack expansion %0 can only appear in a function parameter list, "
"tuple element, or generic argument list", (Type))
"tuple element, or generic argument of a variadic type", (Type))
ERROR(expansion_expr_not_allowed,none,
"value pack expansion can only appear inside a function argument list "
"or tuple element", ())
Expand Down
7 changes: 5 additions & 2 deletions lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "CSDiagnostics.h"
#include "MiscDiagnostics.h"
#include "TypeCheckProtocol.h"
#include "TypeCheckType.h"
#include "TypoCorrection.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTPrinter.h"
Expand Down Expand Up @@ -9173,7 +9174,9 @@ bool OutOfPlaceThenStmtFailure::diagnoseAsError() {
}

bool InvalidTypeSpecializationArity::diagnoseAsError() {
emitDiagnostic(diag::type_parameter_count_mismatch, D->getBaseIdentifier(),
NumParams, NumArgs, NumArgs < NumParams, HasParameterPack);
diagnoseInvalidGenericArguments(getLoc(), D,
NumArgs, NumParams,
HasParameterPack,
/*generic=*/nullptr);
return true;
}
144 changes: 84 additions & 60 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "swift/AST/SourceFile.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/AST/TypeLoc.h"
#include "swift/AST/TypeRepr.h"
#include "swift/AST/TypeResolutionStage.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/Statistic.h"
Expand Down Expand Up @@ -143,8 +144,8 @@ static unsigned getGenericRequirementKind(TypeResolutionOptions options) {
case TypeResolverContext::FunctionInput:
case TypeResolverContext::PackElement:
case TypeResolverContext::TupleElement:
case TypeResolverContext::GenericArgument:
case TypeResolverContext::ProtocolGenericArgument:
case TypeResolverContext::ScalarGenericArgument:
case TypeResolverContext::VariadicGenericArgument:
case TypeResolverContext::ExtensionBinding:
case TypeResolverContext::TypeAliasDecl:
case TypeResolverContext::GenericTypeAliasDecl:
Expand Down Expand Up @@ -667,6 +668,51 @@ bool TypeChecker::checkContextualRequirements(GenericTypeDecl *decl,
llvm_unreachable("invalid requirement check type");
}

void swift::diagnoseInvalidGenericArguments(SourceLoc loc,
ValueDecl *decl,
unsigned argCount,
unsigned paramCount,
bool hasParameterPack,
GenericIdentTypeRepr *generic) {
auto &ctx = decl->getASTContext();
auto &diags = ctx.Diags;

if (!hasParameterPack) {
// For generic types without type parameter packs, we require
// the number of declared generic parameters match the number of
// arguments.
if (argCount < paramCount) {
auto diag = diags
.diagnose(loc, diag::too_few_generic_arguments, decl->getBaseIdentifier(),
argCount, paramCount);
if (generic)
diag.highlight(generic->getAngleBrackets());
} else {
auto diag = diags
.diagnose(loc, diag::too_many_generic_arguments, decl->getBaseIdentifier(),
argCount, paramCount);
if (generic)
diag.highlight(generic->getAngleBrackets());
}
} else {
if (argCount < paramCount - 1) {
auto diag = diags
.diagnose(loc, diag::too_few_generic_arguments_pack, decl->getBaseIdentifier(),
argCount, paramCount - 1);
if (generic)
diag.highlight(generic->getAngleBrackets());
} else {
auto diag = diags
.diagnose(loc, diag::generic_argument_pack_mismatch, decl->getBaseIdentifier());
if (generic)
diag.highlight(generic->getAngleBrackets());
}
}

decl->diagnose(diag::kind_declname_declared_here,
DescriptiveDeclKind::GenericType, decl->getName());
}

/// Apply generic arguments to the given type.
///
/// If the type is itself not generic, this does nothing.
Expand Down Expand Up @@ -747,6 +793,7 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,

auto genericArgs = generic->getGenericArgs();

// Parameterized protocol types have their own code path.
if (auto *protoType = type->getAs<ProtocolType>()) {
auto *protoDecl = protoType->getDecl();

Expand All @@ -761,6 +808,7 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
return ErrorType::get(ctx);
}

// Make sure we have the right number of generic arguments.
if (genericArgs.size() != assocTypes.size()) {
diags.diagnose(loc,
diag::parameterized_protocol_type_argument_count_mismatch,
Expand All @@ -770,45 +818,15 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
return ErrorType::get(ctx);
}

// Build ParameterizedProtocolType if the protocol has a primary associated
// type and we're in a supported context.
if (resolution.getOptions().isConstraintImplicitExistential() &&
!ctx.LangOpts.hasFeature(Feature::ImplicitSome)) {

if (!genericArgs.empty()) {

SmallVector<Type, 2> argTys;
for (auto *genericArg : genericArgs) {
Type argTy = resolution.resolveType(genericArg);
if (!argTy || argTy->hasError())
return ErrorType::get(ctx);

argTys.push_back(argTy);
}

auto parameterized =
ParameterizedProtocolType::get(ctx, protoType, argTys);
diags.diagnose(loc, diag::existential_requires_any, parameterized,
ExistentialType::get(parameterized),
/*isAlias=*/isa<TypeAliasType>(type.getPointer()));
} else {
diags.diagnose(loc, diag::existential_requires_any,
protoDecl->getDeclaredInterfaceType(),
protoDecl->getDeclaredExistentialType(),
/*isAlias=*/isa<TypeAliasType>(type.getPointer()));
}

return ErrorType::get(ctx);
}

// Disallow opaque types anywhere in the structure of the generic arguments
// to a parameterized existential type.
if (options.is(TypeResolverContext::ExistentialConstraint))
options |= TypeResolutionFlags::DisallowOpaqueTypes;
auto argOptions = options.withoutContext().withContext(
TypeResolverContext::ProtocolGenericArgument);
TypeResolverContext::ScalarGenericArgument);
auto genericResolution = resolution.withOptions(argOptions);

// Resolve the generic arguments.
SmallVector<Type, 2> argTys;
for (auto *genericArg : genericArgs) {
Type argTy = genericResolution.resolveType(genericArg, silContext);
Expand All @@ -818,7 +836,18 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
argTys.push_back(argTy);
}

return ParameterizedProtocolType::get(ctx, protoType, argTys);
auto parameterized =
ParameterizedProtocolType::get(ctx, protoType, argTys);

if (resolution.getOptions().isConstraintImplicitExistential() &&
!ctx.LangOpts.hasFeature(Feature::ImplicitSome)) {
diags.diagnose(loc, diag::existential_requires_any, parameterized,
ExistentialType::get(parameterized),
/*isAlias=*/isa<TypeAliasType>(type.getPointer()));
return ErrorType::get(ctx);
}

return parameterized;
}

// We must either have an unbound generic type, or a generic type alias.
Expand All @@ -844,16 +873,20 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
auto *unboundType = type->castTo<UnboundGenericType>();
auto *decl = unboundType->getDecl();

// Make sure we have the right number of generic arguments.
auto genericParams = decl->getGenericParams();
auto hasParameterPack = llvm::any_of(
*genericParams, [](auto *paramDecl) {
return paramDecl->isParameterPack();
});

// Resolve the types of the generic arguments.
// If the type declares at least one parameter pack, allow pack expansions
// anywhere in the argument list. We'll use the PackMatcher to ensure that
// everything lines up. Otherwise, don't allow pack expansions to appear
// at all.
auto argOptions = options.withoutContext().withContext(
TypeResolverContext::GenericArgument);
hasParameterPack
? TypeResolverContext::VariadicGenericArgument
: TypeResolverContext::ScalarGenericArgument);
auto genericResolution = resolution.withOptions(argOptions);

// In SIL mode, Optional<T> interprets T as a SIL type.
Expand All @@ -865,6 +898,7 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
}
}

// Resolve the types of the generic arguments.
SmallVector<Type, 2> args;
for (auto tyR : genericArgs) {
// Propagate failure.
Expand All @@ -875,21 +909,16 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
args.push_back(substTy);
}

// Make sure we have the right number of generic arguments.
if (!hasParameterPack) {
// For generic types without type parameter packs, we require
// the number of declared generic parameters match the number of
// arguments.
if (genericArgs.size() != genericParams->size()) {
if (!options.contains(TypeResolutionFlags::SilenceErrors)) {
diags
.diagnose(loc, diag::type_parameter_count_mismatch, decl->getName(),
genericParams->size(),
genericArgs.size(),
genericArgs.size() < genericParams->size(),
/*hasParameterPack=*/0)
.highlight(generic->getAngleBrackets());
decl->diagnose(diag::kind_declname_declared_here,
DescriptiveDeclKind::GenericType, decl->getName());
diagnoseInvalidGenericArguments(
loc, decl, genericArgs.size(), genericParams->size(),
/*hasParameterPack=*/false, generic);
}
return ErrorType::get(ctx);
}
Expand All @@ -907,17 +936,11 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
}

PackMatcher matcher(params, args, ctx);
if (matcher.match()) {
if (matcher.match() || matcher.pairs.size() != params.size()) {
if (!options.contains(TypeResolutionFlags::SilenceErrors)) {
diags
.diagnose(loc, diag::type_parameter_count_mismatch, decl->getName(),
genericParams->size() - 1,
genericArgs.size(),
genericArgs.size() < genericParams->size(),
/*hasParameterPack=*/1)
.highlight(generic->getAngleBrackets());
decl->diagnose(diag::kind_declname_declared_here,
DescriptiveDeclKind::GenericType, decl->getName());
diagnoseInvalidGenericArguments(
loc, decl, genericArgs.size(), genericParams->size(),
/*hasParameterPack=*/true, generic);
}
return ErrorType::get(ctx);
}
Expand Down Expand Up @@ -953,6 +976,7 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
}
}

// Construct the substituted type.
const auto result = resolution.applyUnboundGenericArguments(
decl, unboundType->getParent(), loc, args);

Expand Down Expand Up @@ -4405,7 +4429,7 @@ NeverNullType
TypeResolver::resolveDictionaryType(DictionaryTypeRepr *repr,
TypeResolutionOptions options) {
auto argOptions = options.withoutContext().withContext(
TypeResolverContext::GenericArgument);
TypeResolverContext::ScalarGenericArgument);

auto keyTy = resolveType(repr->getKey(), argOptions);
if (keyTy->hasError()) {
Expand Down Expand Up @@ -4479,8 +4503,8 @@ NeverNullType TypeResolver::resolveImplicitlyUnwrappedOptionalType(
break;
case TypeResolverContext::PackElement:
case TypeResolverContext::TupleElement:
case TypeResolverContext::GenericArgument:
case TypeResolverContext::ProtocolGenericArgument:
case TypeResolverContext::ScalarGenericArgument:
case TypeResolverContext::VariadicGenericArgument:
case TypeResolverContext::VariadicFunctionInput:
case TypeResolverContext::ForEachStmt:
case TypeResolverContext::ExtensionBinding:
Expand Down
Loading