Skip to content

Parsing generic subscripts #7697

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 3 commits into from
Feb 24, 2017
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
9 changes: 8 additions & 1 deletion include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1213,7 +1213,7 @@ class GenericParamList final :
SourceLoc LAngleLoc,
ArrayRef<GenericTypeParamDecl *> Params,
SourceLoc WhereLoc,
MutableArrayRef<RequirementRepr> Requirements,
ArrayRef<RequirementRepr> Requirements,
SourceLoc RAngleLoc);

MutableArrayRef<GenericTypeParamDecl *> getParams() {
Expand Down Expand Up @@ -1332,6 +1332,11 @@ class GenericParamList final :
return depth;
}

/// Create a copy of the generic parameter list and all of its generic
/// parameter declarations. The copied generic parameters are re-parented
/// to the given DeclContext.
GenericParamList *clone(DeclContext *dc) const;

void print(raw_ostream &OS);
void dump();
};
Expand Down Expand Up @@ -2501,6 +2506,8 @@ class GenericTypeParamDecl : public AbstractTypeParamDecl {
unsigned Index : 16;

public:
static const unsigned InvalidDepth = 0xFFFF;

/// Construct a new generic type parameter.
///
/// \param dc The DeclContext in which the generic type parameter's owner
Expand Down
8 changes: 6 additions & 2 deletions include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -791,13 +791,17 @@ class Parser {
};

bool parseGetSetImpl(ParseDeclOptions Flags,
ParameterList *Indices, TypeLoc ElementTy,
GenericParamList *GenericParams,
ParameterList *Indices,
TypeLoc ElementTy,
ParsedAccessors &accessors,
SourceLoc &LastValidLoc,
SourceLoc StaticLoc, SourceLoc VarLBLoc,
SmallVectorImpl<Decl *> &Decls);
bool parseGetSet(ParseDeclOptions Flags,
ParameterList *Indices, TypeLoc ElementTy,
GenericParamList *GenericParams,
ParameterList *Indices,
TypeLoc ElementTy,
ParsedAccessors &accessors,
SourceLoc StaticLoc, SmallVectorImpl<Decl *> &Decls);
void recordAccessors(AbstractStorageDecl *storage, ParseDeclOptions flags,
Expand Down
64 changes: 62 additions & 2 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ GenericParamList::create(const ASTContext &Context,
SourceLoc LAngleLoc,
ArrayRef<GenericTypeParamDecl *> Params,
SourceLoc WhereLoc,
MutableArrayRef<RequirementRepr> Requirements,
ArrayRef<RequirementRepr> Requirements,
SourceLoc RAngleLoc) {
unsigned Size = totalSizeToAlloc<GenericTypeParamDecl *>(Params.size());
void *Mem = Context.Allocate(Size, alignof(GenericParamList));
Expand All @@ -506,6 +506,66 @@ GenericParamList::create(const ASTContext &Context,
RAngleLoc);
}

GenericParamList *
GenericParamList::clone(DeclContext *dc) const {
auto &ctx = dc->getASTContext();
SmallVector<GenericTypeParamDecl *, 2> params;
for (auto param : getParams()) {
auto *newParam = new (ctx) GenericTypeParamDecl(
dc, param->getName(), param->getNameLoc(),
GenericTypeParamDecl::InvalidDepth,
param->getIndex());
params.push_back(newParam);

SmallVector<TypeLoc, 2> inherited;
for (auto loc : param->getInherited())
inherited.push_back(loc.clone(ctx));
newParam->setInherited(ctx.AllocateCopy(inherited));
}

SmallVector<RequirementRepr, 2> requirements;
for (auto reqt : getRequirements()) {
switch (reqt.getKind()) {
case RequirementReprKind::TypeConstraint: {
auto first = reqt.getSubjectLoc();
auto second = reqt.getConstraintLoc();
reqt = RequirementRepr::getTypeConstraint(
first.clone(ctx),
reqt.getColonLoc(),
second.clone(ctx));
break;
}
case RequirementReprKind::SameType: {
auto first = reqt.getFirstTypeLoc();
auto second = reqt.getSecondTypeLoc();
reqt = RequirementRepr::getSameType(
first.clone(ctx),
reqt.getEqualLoc(),
second.clone(ctx));
break;
}
case RequirementReprKind::LayoutConstraint: {
auto first = reqt.getSubjectLoc();
auto layout = reqt.getLayoutConstraintLoc();
reqt = RequirementRepr::getLayoutConstraint(
first.clone(ctx),
reqt.getColonLoc(),
layout);
break;
}
}

requirements.push_back(reqt);
}

return GenericParamList::create(ctx,
getLAngleLoc(),
params,
getWhereLoc(),
requirements,
getRAngleLoc());
}

void GenericParamList::addTrailingWhereClause(
ASTContext &ctx,
SourceLoc trailingWhereLoc,
Expand Down Expand Up @@ -3812,7 +3872,7 @@ ParamDecl::ParamDecl(ParamDecl *PD)
DefaultValueAndIsVariadic(nullptr, PD->DefaultValueAndIsVariadic.getInt()),
IsTypeLocImplicit(PD->IsTypeLocImplicit),
defaultArgumentKind(PD->defaultArgumentKind) {
typeLoc = PD->getTypeLoc();
typeLoc = PD->getTypeLoc().clone(PD->getASTContext());
if (PD->hasInterfaceType())
setInterfaceType(PD->getInterfaceType());
}
Expand Down
3 changes: 2 additions & 1 deletion lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1181,7 +1181,8 @@ CanType TypeBase::getCanonicalType() {
case TypeKind::GenericTypeParam: {
GenericTypeParamType *gp = cast<GenericTypeParamType>(this);
auto gpDecl = gp->getDecl();
assert(gpDecl->getDepth() != 0xFFFF && "parameter hasn't been validated");
assert(gpDecl->getDepth() != GenericTypeParamDecl::InvalidDepth &&
"parameter hasn't been validated");
Result = GenericTypeParamType::get(gpDecl->getDepth(), gpDecl->getIndex(),
gpDecl->getASTContext());
break;
Expand Down
85 changes: 67 additions & 18 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3270,8 +3270,10 @@ ParserResult<TypeDecl> Parser::parseDeclAssociatedType(Parser::ParseDeclOptions
/// This function creates an accessor function (with no body) for a computed
/// property or subscript.
static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, ParameterList *param,
GenericParamList *GenericParams,
ParameterList *Indices,
TypeLoc ElementTy,
ParameterList *Indices, SourceLoc StaticLoc,
SourceLoc StaticLoc,
Parser::ParseDeclOptions Flags,
AccessorKind Kind,
AddressorKind addressorKind,
Expand Down Expand Up @@ -3399,8 +3401,11 @@ static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, ParameterList *param,
/*FIXME FuncLoc=*/DeclLoc, Identifier(),
/*NameLoc=*/DeclLoc, /*Throws=*/false,
/*ThrowsLoc=*/SourceLoc(), AccessorKeywordLoc,
/*GenericParams=*/nullptr,
Params, ReturnType, P->CurDeclContext);
(GenericParams
? GenericParams->clone(P->CurDeclContext)
: nullptr),
Params, ReturnType,
P->CurDeclContext);

// Non-static set/willSet/didSet/materializeForSet/mutableAddress
// default to mutating. get/address default to
Expand Down Expand Up @@ -3644,7 +3649,9 @@ static void diagnoseRedundantAccessors(Parser &P, SourceLoc loc,
/// \brief Parse a get-set clause, optionally containing a getter, setter,
/// willSet, and/or didSet clauses. 'Indices' is a paren or tuple pattern,
/// specifying the index list for a subscript.
bool Parser::parseGetSetImpl(ParseDeclOptions Flags, ParameterList *Indices,
bool Parser::parseGetSetImpl(ParseDeclOptions Flags,
GenericParamList *GenericParams,
ParameterList *Indices,
TypeLoc ElementTy, ParsedAccessors &accessors,
SourceLoc &LastValidLoc, SourceLoc StaticLoc,
SourceLoc VarLBLoc,
Expand Down Expand Up @@ -3718,7 +3725,8 @@ bool Parser::parseGetSetImpl(ParseDeclOptions Flags, ParameterList *Indices,
= parseOptionalAccessorArgument(Loc, ElementTy, *this, Kind);

// Set up a function declaration.
TheDecl = createAccessorFunc(Loc, ValueNameParams, ElementTy, Indices,
TheDecl = createAccessorFunc(Loc, ValueNameParams,
GenericParams, Indices, ElementTy,
StaticLoc, Flags, Kind, addressorKind, this,
AccessorKeywordLoc);
TheDecl->getAttrs() = Attributes;
Expand Down Expand Up @@ -3849,7 +3857,8 @@ bool Parser::parseGetSetImpl(ParseDeclOptions Flags, ParameterList *Indices,
}

// Set up a function declaration.
TheDecl = createAccessorFunc(Loc, ValueNamePattern, ElementTy, Indices,
TheDecl = createAccessorFunc(Loc, ValueNamePattern,
GenericParams, Indices, ElementTy,
StaticLoc, Flags, Kind, addressorKind, this,
AccessorKeywordLoc);
TheDecl->getAttrs() = Attributes;
Expand All @@ -3862,6 +3871,10 @@ bool Parser::parseGetSetImpl(ParseDeclOptions Flags, ParameterList *Indices,
for (auto PL : TheDecl->getParameterLists())
addParametersToScope(PL);

if (TheDecl->isGeneric())
for (auto *GP : TheDecl->getGenericParams()->getParams())
addToScope(GP);

// Establish the new context.
ParseFunctionBody CC(*this, TheDecl);

Expand Down Expand Up @@ -3896,15 +3909,17 @@ bool Parser::parseGetSetImpl(ParseDeclOptions Flags, ParameterList *Indices,
return false;
}

bool Parser::parseGetSet(ParseDeclOptions Flags, ParameterList *Indices,
bool Parser::parseGetSet(ParseDeclOptions Flags,
GenericParamList *GenericParams,
ParameterList *Indices,
TypeLoc ElementTy, ParsedAccessors &accessors,
SourceLoc StaticLoc,
SmallVectorImpl<Decl *> &Decls) {
accessors.LBLoc = consumeToken(tok::l_brace);
SourceLoc LastValidLoc = accessors.LBLoc;
bool Invalid = parseGetSetImpl(Flags, Indices, ElementTy, accessors,
LastValidLoc, StaticLoc, accessors.LBLoc,
Decls);
bool Invalid = parseGetSetImpl(Flags, GenericParams, Indices, ElementTy,
accessors, LastValidLoc, StaticLoc,
accessors.LBLoc, Decls);

// Parse the final '}'.
if (Invalid)
Expand Down Expand Up @@ -3990,7 +4005,8 @@ VarDecl *Parser::parseDeclVarGetSet(Pattern *pattern,

// Parse getter and setter.
ParsedAccessors accessors;
if (parseGetSet(Flags, /*Indices=*/nullptr, TyLoc, accessors, StaticLoc,
if (parseGetSet(Flags, /*GenericParams=*/nullptr,
/*Indices=*/nullptr, TyLoc, accessors, StaticLoc,
Decls))
Invalid = true;

Expand Down Expand Up @@ -4058,11 +4074,16 @@ void Parser::ParsedAccessors::record(Parser &P, AbstractStorageDecl *storage,
}
};

GenericParamList *genericParams = nullptr;
if (auto *subscript = dyn_cast<SubscriptDecl>(storage))
genericParams = subscript->getGenericParams();

// Create an implicit accessor declaration.
auto createImplicitAccessor =
[&](AccessorKind kind, AddressorKind addressorKind,
ParameterList *argList) -> FuncDecl* {
auto accessor = createAccessorFunc(SourceLoc(), argList, elementTy, indices,
auto accessor = createAccessorFunc(SourceLoc(), argList,
genericParams, indices, elementTy,
staticLoc, flags, kind, addressorKind,
&P, SourceLoc());
accessor->setImplicit();
Expand Down Expand Up @@ -5409,7 +5430,7 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) {
/// decl-subscript:
/// subscript-head get-set
/// subscript-head
/// 'subscript' attribute-list parameter-clause '->' type
/// attribute-list? 'subscript' parameter-clause '->' type
/// \endverbatim
ParserResult<SubscriptDecl>
Parser::parseDeclSubscript(ParseDeclOptions Flags,
Expand All @@ -5418,6 +5439,20 @@ Parser::parseDeclSubscript(ParseDeclOptions Flags,
ParserStatus Status;
SourceLoc SubscriptLoc = consumeToken(tok::kw_subscript);

// Parse the generic-params, if present.
Optional<Scope> GenericsScope;
GenericsScope.emplace(this, ScopeKind::Generics);
GenericParamList *GenericParams;
bool GPHasCodeCompletion = false;

auto Result = maybeParseGenericParams();
GenericParams = Result.getPtrOrNull();
GPHasCodeCompletion |= Result.hasCodeCompletion();

if (GPHasCodeCompletion && !CodeCompletion)
return makeParserCodeCompletionStatus();

// Parse the parameter list.
SmallVector<Identifier, 4> argumentNames;
ParserResult<ParameterList> Indices
= parseSingleParameterClause(ParameterContextKind::Subscript,
Expand All @@ -5438,19 +5473,32 @@ Parser::parseDeclSubscript(ParseDeclOptions Flags,
if (ElementTy.isNull() || ElementTy.hasCodeCompletion())
return ParserStatus(ElementTy);


diagnoseWhereClauseInGenericParamList(GenericParams);

// Parse a 'where' clause if present, adding it to our GenericParamList.
if (Tok.is(tok::kw_where)) {
auto whereStatus = parseFreestandingGenericWhereClause(GenericParams);
if (whereStatus.shouldStopParsing())
return whereStatus;
}

// Build an AST for the subscript declaration.
DeclName name = DeclName(Context, Context.Id_subscript, argumentNames);
auto *Subscript = new (Context) SubscriptDecl(name,
SubscriptLoc, Indices.get(),
ArrowLoc, ElementTy.get(),
CurDeclContext,
/*GenericParams=*/nullptr);
GenericParams);
Subscript->getAttrs() = Attributes;


// Code completion for the generic type params.
//
// FIXME: What is this?
if (GPHasCodeCompletion)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nkcsgexi How do I test these 'code completion' code paths in the parser correctly?

CodeCompletion->setDelayedParsedDecl(Subscript);

Decls.push_back(Subscript);


// '{'
// Parse getter and setter.
ParsedAccessors accessors;
Expand All @@ -5464,7 +5512,8 @@ Parser::parseDeclSubscript(ParseDeclOptions Flags,
diagnose(Tok, diag::expected_lbrace_subscript);
Status.setIsParseError();
} else {
if (parseGetSet(Flags, Indices.get(), ElementTy.get(),
if (parseGetSet(Flags, GenericParams,
Indices.get(), ElementTy.get(),
accessors, /*StaticLoc=*/SourceLoc(), Decls))
Status.setIsParseError();
}
Expand Down
8 changes: 4 additions & 4 deletions lib/Parse/ParseGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,10 @@ Parser::parseGenericParameters(SourceLoc LAngleLoc) {
// We always create generic type parameters with a depth of zero.
// Semantic analysis fills in the depth when it processes the generic
// parameter list.
auto Param = new (Context) GenericTypeParamDecl(CurDeclContext, Name,
NameLoc,
/*Bogus depth=*/0xFFFF,
GenericParams.size());
auto Param = new (Context) GenericTypeParamDecl(
CurDeclContext, Name, NameLoc,
GenericTypeParamDecl::InvalidDepth,
GenericParams.size());
if (!Inherited.empty())
Param->setInherited(Context.AllocateCopy(Inherited));
GenericParams.push_back(Param);
Expand Down
12 changes: 11 additions & 1 deletion lib/Sema/CodeSynthesis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,10 +326,20 @@ static FuncDecl *createMaterializeForSetPrototype(AbstractStorageDecl *storage,
};
Type retTy = TupleType::get(retElts, ctx);

// Accessors of generic subscripts get a copy of the subscript's
// generic parameter list, because they're not nested inside the
// subscript.
GenericParamList *genericParams = nullptr;
if (auto *subscript = dyn_cast<SubscriptDecl>(storage))
genericParams = subscript->getGenericParams();

auto *materializeForSet = FuncDecl::create(
ctx, /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None, loc,
Identifier(), loc, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
/*AccessorKeywordLoc=*/SourceLoc(), /*GenericParams=*/nullptr,
/*AccessorKeywordLoc=*/SourceLoc(),
(genericParams
? genericParams->clone(DC)
: nullptr),
params, TypeLoc::withoutLoc(retTy), DC);
materializeForSet->setImplicit();

Expand Down
6 changes: 5 additions & 1 deletion lib/Sema/TypeCheckGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -788,7 +788,11 @@ void TypeChecker::configureInterfaceType(AbstractFunctionDecl *func,
if (initFuncTy)
cast<ConstructorDecl>(func)->setInitializerInterfaceType(initFuncTy);

checkReferencedGenericParams(func, sig, *this);
// We get bogus errors here with generic subscript materializeForSet.
if (!isa<FuncDecl>(func) ||
cast<FuncDecl>(func)->getAccessorKind() !=
AccessorKind::IsMaterializeForSet)
checkReferencedGenericParams(func, sig, *this);
}

///
Expand Down
3 changes: 2 additions & 1 deletion test/Constraints/invalid_constraint_lookup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ func f<U: P>(_ rhs: U) -> X<U.A> { // expected-error {{use of undeclared type 'X
}

struct Zzz<T> {
subscript (a: Foo) -> Zzz<T> { // expected-error {{use of undeclared type 'Foo'}}
// FIXME: Duplicate diagnostics
subscript (a: Foo) -> Zzz<T> { // expected-error 2{{use of undeclared type 'Foo'}}
get: // expected-error {{expected '{' to start getter definition}}
set:
for i in value {}
Expand Down
Loading