Factor parsing of pattern-tuple-element into its own routine.

This simple refactor makes pattern-tuple-element available for re-use
in closure expressions. As a drive-by, diagnose non-final ellipses via
diagnose() rather than via assert(), the latter being considered
rather unfriendly. Also, take pains to restore AST invariants after
such an error.


Swift SVN r5163
This commit is contained in:
Doug Gregor
2013-05-13 21:32:33 +00:00
parent 656892b30d
commit 8372f46fb4
6 changed files with 110 additions and 53 deletions

View File

@@ -394,6 +394,8 @@ ERROR(expected_rparen_tuple_pattern_list,pattern_parsing,non,
"expected ')' at end of tuple pattern", ()) "expected ')' at end of tuple pattern", ())
ERROR(untyped_pattern_ellipsis,pattern_parsing,none, ERROR(untyped_pattern_ellipsis,pattern_parsing,none,
"'...' cannot be applied to a subpattern which is not explicitly typed", ()) "'...' cannot be applied to a subpattern which is not explicitly typed", ())
ERROR(ellipsis_pattern_not_at_end,pattern_parsing,none,
"variadic arguments '...' must come at the end of the pattern", ())
ERROR(non_func_decl_pattern_init,pattern_parsing,none, ERROR(non_func_decl_pattern_init,pattern_parsing,none,
"tuple element in pattern cannot have a default initializer", ()) "tuple element in pattern cannot have a default initializer", ())

View File

@@ -139,6 +139,8 @@ public:
/// An element of a tuple pattern. /// An element of a tuple pattern.
class TuplePatternElt { class TuplePatternElt {
Pattern *ThePattern; Pattern *ThePattern;
// FIXME: Init and VarargBaseType can be collapsed into one field.
ExprHandle *Init; ExprHandle *Init;
Type VarargBaseType; Type VarargBaseType;
@@ -153,6 +155,13 @@ public:
bool isVararg() const { return !VarargBaseType.isNull(); } bool isVararg() const { return !VarargBaseType.isNull(); }
Type getVarargBaseType() const { return VarargBaseType; } Type getVarargBaseType() const { return VarargBaseType; }
void setVarargBaseType(Type ty) { VarargBaseType = ty; } void setVarargBaseType(Type ty) { VarargBaseType = ty; }
/// \brief Revert this variadic tuple pattern element to a
/// non-variadic version.
///
/// Used for error recovery, when we've detected that the element
/// is not the last one.
void revertToNonVariadic();
}; };
/// A pattern consisting of a tuple of patterns. /// A pattern consisting of a tuple of patterns.

View File

@@ -175,6 +175,18 @@ Identifier Pattern::getBoundName() const {
return Identifier(); return Identifier();
} }
void TuplePatternElt::revertToNonVariadic() {
assert(VarargBaseType && "Not a variadic element");
// Fix the pattern.
auto typedPattern = cast<TypedPattern>(ThePattern);
typedPattern->getTypeLoc()
= TypeLoc(VarargBaseType, typedPattern->getTypeLoc().getSourceRange());
// Clear out the variadic base type.
VarargBaseType = Type();
}
/// Allocate a new pattern that matches a tuple. /// Allocate a new pattern that matches a tuple.
TuplePattern *TuplePattern::create(ASTContext &C, SourceLoc lp, TuplePattern *TuplePattern::create(ASTContext &C, SourceLoc lp,
ArrayRef<TuplePatternElt> elts, ArrayRef<TuplePatternElt> elts,

View File

@@ -305,73 +305,97 @@ NullablePtr<Pattern> Parser::parsePatternAtom() {
} }
} }
Optional<TuplePatternElt> Parser::parsePatternTupleElement(bool allowInitExpr) {
// Parse the pattern.
NullablePtr<Pattern> pattern = parsePattern();
if (pattern.isNull())
return Nothing;
// Parse the optional initializer.
ExprHandle *init = nullptr;
if (Tok.is(tok::equal)) {
SourceLoc EqualLoc = consumeToken();
if (!allowInitExpr) {
diagnose(EqualLoc, diag::non_func_decl_pattern_init);
}
NullablePtr<Expr> initR = parseExpr(diag::expected_initializer_expr);
// FIXME: Silently dropping initializer expressions where they aren't
// permitted.
if (allowInitExpr && initR.isNonNull())
init = ExprHandle::get(Context, initR.get());
}
// The result, should we succeed.
TuplePatternElt result(pattern.get(), init);
// If there is no ellipsis, we're done.
if (Tok.isNot(tok::ellipsis))
return result;
// An element cannot have both an initializer and an ellipsis.
if (init) {
diagnose(Tok.getLoc(), diag::tuple_ellipsis_init)
.highlight(init->getExpr()->getSourceRange());
consumeToken(tok::ellipsis);
return result;
}
SourceLoc ellipsisLoc = consumeToken(tok::ellipsis);
// An ellipsis element shall have a specified element type.
// FIXME: This seems unnecessary.
TypedPattern *typedPattern = dyn_cast<TypedPattern>(result.getPattern());
if (!typedPattern) {
diagnose(ellipsisLoc, diag::untyped_pattern_ellipsis)
.highlight(result.getPattern()->getSourceRange());
return result;
}
// Update the element and pattern to make it variadic.
Type subTy = typedPattern->getTypeLoc().getType();
result.setVarargBaseType(subTy);
typedPattern->getTypeLoc()
= TypeLoc(ArraySliceType::get(subTy, Context),
typedPattern->getTypeLoc().getSourceRange());
return result;
}
/// Parse a tuple pattern. /// Parse a tuple pattern.
/// ///
/// pattern-tuple: /// pattern-tuple:
//// '(' pattern-tuple-body? ')' //// '(' pattern-tuple-body? ')'
/// pattern-tuple-body: /// pattern-tuple-body:
/// pattern-tuple-element (',' pattern-tuple-body)* /// pattern-tuple-element (',' pattern-tuple-body)*
/// pattern-tuple-element:
/// pattern ('=' expr)?
NullablePtr<Pattern> Parser::parsePatternTuple(bool AllowInitExpr) { NullablePtr<Pattern> Parser::parsePatternTuple(bool AllowInitExpr) {
SourceLoc RPLoc, LPLoc = consumeToken(tok::l_paren); SourceLoc RPLoc, LPLoc = consumeToken(tok::l_paren);
// Parse all the elements. // Parse all the elements.
SmallVector<TuplePatternElt, 8> elts; SmallVector<TuplePatternElt, 8> elts;
bool hadEllipsis = false; bool Invalid = parseList(tok::r_paren, LPLoc, RPLoc,
bool Invalid = false;
Invalid |= parseList(tok::r_paren, LPLoc, RPLoc,
tok::comma, /*OptionalSep=*/false, tok::comma, /*OptionalSep=*/false,
diag::expected_rparen_tuple_pattern_list, diag::expected_rparen_tuple_pattern_list,
[&] () -> bool { [&] () -> bool {
NullablePtr<Pattern> pattern = parsePattern(); // Parse the pattern tuple element.
ExprHandle *init = nullptr; Optional<TuplePatternElt> elt = parsePatternTupleElement(AllowInitExpr);
if (!elt)
if (pattern.isNull())
return true; return true;
if (Tok.is(tok::equal)) { // Variadic elements must come last.
SourceLoc EqualLoc = consumeToken(); // FIXME: Unnecessary restriction. It makes conversion more interesting,
if (!AllowInitExpr) { // but is not complicated to support.
diagnose(EqualLoc, diag::non_func_decl_pattern_init); if (!elts.empty() && elts.back().isVararg()) {
Invalid |= true;
}
NullablePtr<Expr> initR = parseExpr(diag::expected_initializer_expr);
if (initR.isNull())
return true;
init = ExprHandle::get(Context, initR.get());
}
elts.push_back(TuplePatternElt(pattern.get(), init));
if (Tok.isNot(tok::ellipsis))
return false;
if (elts.back().getInit()) {
diagnose(Tok.getLoc(), diag::tuple_ellipsis_init);
return true;
}
hadEllipsis = true;
consumeToken(tok::ellipsis);
// FIXME -- add diag
assert(Tok.is(tok::r_paren));
TypedPattern *subpattern =
dyn_cast<TypedPattern>(elts.back().getPattern());
if (!subpattern) {
diagnose(elts.back().getPattern()->getLoc(), diagnose(elts.back().getPattern()->getLoc(),
diag::untyped_pattern_ellipsis); diag::ellipsis_pattern_not_at_end)
return true; .highlight(elt->getPattern()->getSourceRange());
// Make the previous element non-variadic.
elts.back().revertToNonVariadic();
} }
Type subTy = subpattern->getTypeLoc().getType(); // Add this element to the list.
elts.back().setVarargBaseType(subTy); elts.push_back(*elt);
// FIXME: This is wrong for TypeLoc info.
subpattern->getTypeLoc() =
TypeLoc::withoutLoc(ArraySliceType::get(subTy, Context));
return false; return false;
}); });
@@ -382,7 +406,7 @@ NullablePtr<Pattern> Parser::parsePatternTuple(bool AllowInitExpr) {
if (elts.size() == 1 && if (elts.size() == 1 &&
elts[0].getInit() == nullptr && elts[0].getInit() == nullptr &&
elts[0].getPattern()->getBoundName().empty() && elts[0].getPattern()->getBoundName().empty() &&
!hadEllipsis) !elts[0].isVararg())
return new (Context) ParenPattern(LPLoc, elts[0].getPattern(), RPLoc); return new (Context) ParenPattern(LPLoc, elts[0].getPattern(), RPLoc);
return TuplePattern::create(Context, LPLoc, elts, RPLoc); return TuplePattern::create(Context, LPLoc, elts, RPLoc);

View File

@@ -159,7 +159,7 @@ SourceLoc Parser::consumeStartingLess() {
// Skip the starting '<' in the existing token. // Skip the starting '<' in the existing token.
SourceLoc Loc = Tok.getLoc(); SourceLoc Loc = Tok.getLoc();
StringRef Remaining =Tok.getText().substr(1); StringRef Remaining = Tok.getText().substr(1);
Tok.setToken(L->getTokenKind(Remaining), Remaining); Tok.setToken(L->getTokenKind(Remaining), Remaining);
return Loc; return Loc;
} }
@@ -172,7 +172,7 @@ SourceLoc Parser::consumeStartingGreater() {
// Skip the starting '>' in the existing token. // Skip the starting '>' in the existing token.
SourceLoc Loc = Tok.getLoc(); SourceLoc Loc = Tok.getLoc();
StringRef Remaining =Tok.getText().substr(1); StringRef Remaining = Tok.getText().substr(1);
Tok.setToken(L->getTokenKind(Remaining), Remaining); Tok.setToken(L->getTokenKind(Remaining), Remaining);
return Loc; return Loc;
} }

View File

@@ -343,6 +343,16 @@ public:
SmallVectorImpl<Pattern*> &bodyPatterns, SmallVectorImpl<Pattern*> &bodyPatterns,
TypeLoc &retLoc); TypeLoc &retLoc);
NullablePtr<Pattern> parsePattern(); NullablePtr<Pattern> parsePattern();
/// Parse a tuple pattern element.
///
/// pattern-tuple-element:
/// pattern ('=' expr)?
///
/// \param allowInitExpr Whether to allow initializers.
///
/// \returns The tuple pattern element, if successful.
Optional<TuplePatternElt> parsePatternTupleElement(bool allowInitExpr);
NullablePtr<Pattern> parsePatternTuple(bool AllowInitExpr); NullablePtr<Pattern> parsePatternTuple(bool AllowInitExpr);
NullablePtr<Pattern> parsePatternAtom(); NullablePtr<Pattern> parsePatternAtom();
NullablePtr<Pattern> parsePatternIdentifier(); NullablePtr<Pattern> parsePatternIdentifier();