mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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:
@@ -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", ())
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user