From 84634ac25da26513935d62177aedff1a01fee668 Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Mon, 9 Mar 2015 22:51:23 -0400 Subject: [PATCH 01/10] Disallow line terminator after arrow function parameters, before => Closes #2282 --- src/compiler/parser.ts | 327 +++++++++--------- ...sallowLineTerminatorBeforeArrow.errors.txt | 70 ++++ .../disallowLineTerminatorBeforeArrow.js | 60 ++++ .../disallowLineTerminatorBeforeArrow.ts | 22 ++ 4 files changed, 318 insertions(+), 161 deletions(-) create mode 100644 tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt create mode 100644 tests/baselines/reference/disallowLineTerminatorBeforeArrow.js create mode 100644 tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 7f89ff6153bc3..fc02c3f3eef3f 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -8,7 +8,7 @@ module ts { export function getNodeConstructor(kind: SyntaxKind): new () => Node { return nodeConstructors[kind] || (nodeConstructors[kind] = objectAllocator.getNodeConstructor(kind)); } - + export function createNode(kind: SyntaxKind): Node { return new (getNodeConstructor(kind))(); } @@ -369,7 +369,7 @@ module ts { function fixupParentReferences(sourceFile: SourceFile) { // normally parent references are set during binding. However, for clients that only need - // a syntax tree, and no semantic features, then the binding process is an unnecessary + // a syntax tree, and no semantic features, then the binding process is an unnecessary // overhead. This functions allows us to set all the parents, without all the expense of // binding. @@ -379,7 +379,7 @@ module ts { function visitNode(n: Node): void { // walk down setting parents that differ from the parent we think it should be. This - // allows us to quickly bail out of setting parents for subtrees during incremental + // allows us to quickly bail out of setting parents for subtrees during incremental // parsing if (n.parent !== parent) { n.parent = parent; @@ -417,7 +417,7 @@ module ts { var text = oldText.substring(node.pos, node.end); } - // Ditch any existing LS children we may have created. This way we can avoid + // Ditch any existing LS children we may have created. This way we can avoid // moving them forward. node._children = undefined; node.pos += delta; @@ -455,9 +455,9 @@ module ts { // We may need to update both the 'pos' and the 'end' of the element. - // If the 'pos' is before the start of the change, then we don't need to touch it. - // If it isn't, then the 'pos' must be inside the change. How we update it will - // depend if delta is positive or negative. If delta is positive then we have + // If the 'pos' is before the start of the change, then we don't need to touch it. + // If it isn't, then the 'pos' must be inside the change. How we update it will + // depend if delta is positive or negative. If delta is positive then we have // something like: // // -------------------AAA----------------- @@ -471,7 +471,7 @@ module ts { // -------------------XXXYYYYYYY----------------- // -------------------ZZZ----------------- // - // In this case, any element that started in the 'X' range will keep its position. + // In this case, any element that started in the 'X' range will keep its position. // However any element htat started after that will have their pos adjusted to be // at the end of the new range. i.e. any node that started in the 'Y' range will // be adjusted to have their start at the end of the 'Z' range. @@ -481,7 +481,7 @@ module ts { element.pos = Math.min(element.pos, changeRangeNewEnd); // If the 'end' is after the change range, then we always adjust it by the delta - // amount. However, if the end is in the change range, then how we adjust it + // amount. However, if the end is in the change range, then how we adjust it // will depend on if delta is positive or negative. If delta is positive then we // have something like: // @@ -496,7 +496,7 @@ module ts { // -------------------XXXYYYYYYY----------------- // -------------------ZZZ----------------- // - // In this case, any element that ended in the 'X' range will keep its position. + // In this case, any element that ended in the 'X' range will keep its position. // However any element htat ended after that will have their pos adjusted to be // at the end of the new range. i.e. any node that ended in the 'Y' range will // be adjusted to have their end at the end of the 'Z' range. @@ -505,7 +505,7 @@ module ts { element.end += delta; } else { - // Element ends in the change range. The element will keep its position if + // Element ends in the change range. The element will keep its position if // possible. Or Move backward to the new-end if it's in the 'Y' range. element.end = Math.min(element.end, changeRangeNewEnd); } @@ -544,7 +544,7 @@ module ts { function visitNode(child: IncrementalNode) { Debug.assert(child.pos <= child.end); if (child.pos > changeRangeOldEnd) { - // Node is entirely past the change range. We need to move both its pos and + // Node is entirely past the change range. We need to move both its pos and // end, forward or backward appropriately. moveElementEntirelyPastChangeRange(child, /*isArray:*/ false, delta, oldText, newText, aggressiveChecks); return; @@ -607,12 +607,12 @@ module ts { // If the text changes with an insertion of / just before the semicolon then we end up with: // void foo() { //; } // - // If we were to just use the changeRange a is, then we would not rescan the { token + // If we were to just use the changeRange a is, then we would not rescan the { token // (as it does not intersect the actual original change range). Because an edit may // change the token touching it, we actually need to look back *at least* one token so - // that the prior token sees that change. + // that the prior token sees that change. let maxLookahead = 1; - + let start = changeRange.span.start; // the first iteration aligns us with the change start. subsequent iteration move us to @@ -676,7 +676,7 @@ module ts { return; } - // If the child intersects this position, then this node is currently the nearest + // If the child intersects this position, then this node is currently the nearest // node that starts before the position. if (child.pos <= position) { if (child.pos >= bestResult.pos) { @@ -687,7 +687,7 @@ module ts { // Now, the node may overlap the position, or it may end entirely before the // position. If it overlaps with the position, then either it, or one of its - // children must be the nearest node before the position. So we can just + // children must be the nearest node before the position. So we can just // recurse into this child to see if we can find something better. if (position < child.end) { // The nearest node is either this child, or one of the children inside @@ -703,15 +703,15 @@ module ts { Debug.assert(child.end <= position); // The child ends entirely before this position. Say you have the following // (where $ is the position) - // - // ? $ : <...> <...> // - // We would want to find the nearest preceding node in "complex expr 2". + // ? $ : <...> <...> + // + // We would want to find the nearest preceding node in "complex expr 2". // To support that, we keep track of this node, and once we're done searching // for a best node, we recurse down this node to see if we can find a good // result in it. // - // This approach allows us to quickly skip over nodes that are entirely + // This approach allows us to quickly skip over nodes that are entirely // before the position, while still allowing us to find any nodes in the // last one that might be what we want. lastNodeEntirelyBeforePosition = child; @@ -744,13 +744,13 @@ module ts { } } - // Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter + // Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter // indicates what changed between the 'text' that this SourceFile has and the 'newText'. - // The SourceFile will be created with the compiler attempting to reuse as many nodes from + // The SourceFile will be created with the compiler attempting to reuse as many nodes from // this file as possible. // // Note: this function mutates nodes from this SourceFile. That means any existing nodes - // from this SourceFile that are being held onto may change as a result (including + // from this SourceFile that are being held onto may change as a result (including // becoming detached from any SourceFile). It is recommended that this SourceFile not // be used once 'update' is called on it. export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile { @@ -769,7 +769,7 @@ module ts { } // Make sure we're not trying to incrementally update a source file more than once. Once - // we do an update the original source file is considered unusbale from that point onwards. + // we do an update the original source file is considered unusbale from that point onwards. // // This is because we do incremental parsing in-place. i.e. we take nodes from the old // tree and give them new positions and parents. From that point on, trusting the old @@ -781,24 +781,24 @@ module ts { let oldText = sourceFile.text; let syntaxCursor = createSyntaxCursor(sourceFile); - // Make the actual change larger so that we know to reparse anything whose lookahead + // Make the actual change larger so that we know to reparse anything whose lookahead // might have intersected the change. let changeRange = extendToAffectedRange(sourceFile, textChangeRange); checkChangeRange(sourceFile, newText, changeRange, aggressiveChecks); - // Ensure that extending the affected range only moved the start of the change range + // Ensure that extending the affected range only moved the start of the change range // earlier in the file. Debug.assert(changeRange.span.start <= textChangeRange.span.start); Debug.assert(textSpanEnd(changeRange.span) === textSpanEnd(textChangeRange.span)); Debug.assert(textSpanEnd(textChangeRangeNewSpan(changeRange)) === textSpanEnd(textChangeRangeNewSpan(textChangeRange))); - // The is the amount the nodes after the edit range need to be adjusted. It can be + // The is the amount the nodes after the edit range need to be adjusted. It can be // positive (if the edit added characters), negative (if the edit deleted characters) // or zero (if this was a pure overwrite with nothing added/removed). let delta = textChangeRangeNewSpan(changeRange).length - changeRange.span.length; // If we added or removed characters during the edit, then we need to go and adjust all - // the nodes after the edit. Those nodes may move forward (if we inserted chars) or they + // the nodes after the edit. Those nodes may move forward (if we inserted chars) or they // may move backward (if we deleted chars). // // Doing this helps us out in two ways. First, it means that any nodes/tokens we want @@ -811,7 +811,7 @@ module ts { // // We will also adjust the positions of nodes that intersect the change range as well. // By doing this, we ensure that all the positions in the old tree are consistent, not - // just the positions of nodes entirely before/after the change range. By being + // just the positions of nodes entirely before/after the change range. By being // consistent, we can then easily map from positions to nodes in the old tree easily. // // Also, mark any syntax elements that intersect the changed span. We know, up front, @@ -822,15 +822,15 @@ module ts { // Now that we've set up our internal incremental state just proceed and parse the // source file in the normal fashion. When possible the parser will retrieve and // reuse nodes from the old tree. - // + // // Note: passing in 'true' for setNodeParents is very important. When incrementally // parsing, we will be reusing nodes from the old tree, and placing it into new - // parents. If we don't set the parents now, we'll end up with an observably - // inconsistent tree. Setting the parents on the new tree should be very fast. We + // parents. If we don't set the parents now, we'll end up with an observably + // inconsistent tree. Setting the parents on the new tree should be very fast. We // will immediately bail out of walking any subtrees when we can see that their parents // are already correct. - let result = parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /* setParentNode */ true) - + let result = parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /* setParentNode */ true) + return result; } @@ -885,13 +885,13 @@ module ts { return { currentNode(position: number) { - // Only compute the current node if the position is different than the last time - // we were asked. The parser commonly asks for the node at the same position + // Only compute the current node if the position is different than the last time + // we were asked. The parser commonly asks for the node at the same position // twice. Once to know if can read an appropriate list element at a certain point, // and then to actually read and consume the node. if (position !== lastQueriedPosition) { - // Much of the time the parser will need the very next node in the array that - // we just returned a node from.So just simply check for that case and move + // Much of the time the parser will need the very next node in the array that + // we just returned a node from.So just simply check for that case and move // forward in the array instead of searching for the node again. if (current && current.end === position && currentArrayIndex < (currentArray.length - 1)) { currentArrayIndex++; @@ -905,7 +905,7 @@ module ts { } } - // Cache this query so that we don't do any extra work if the parser calls back + // Cache this query so that we don't do any extra work if the parser calls back // into us. Note: this is very common as the parser will make pairs of calls like // 'isListElement -> parseListElement'. If we were unable to find a node when // called with 'isListElement', we don't want to redo the work when parseListElement @@ -917,7 +917,7 @@ module ts { return current; } }; - + // Finds the highest element in the tree we can find that starts at the provided position. // The element must be a direct child of some node list in the tree. This way after we // return it, we can easily return its next sibling in the list. @@ -960,7 +960,7 @@ module ts { } else { if (child.pos < position && position < child.end) { - // Position in somewhere within this child. Search in it and + // Position in somewhere within this child. Search in it and // stop searching in this array. forEachChild(child, visitNode, visitArray); return true; @@ -1007,10 +1007,10 @@ module ts { // Whether or not we are in strict parsing mode. All that changes in strict parsing mode is // that some tokens that would be considered identifiers may be considered keywords. // - // When adding more parser context flags, consider which is the more common case that the + // When adding more parser context flags, consider which is the more common case that the // flag will be in. This should be hte 'false' state for that flag. The reason for this is // that we don't store data in our nodes unless the value is in the *non-default* state. So, - // for example, more often than code 'allows-in' (or doesn't 'disallow-in'). We opt for + // for example, more often than code 'allows-in' (or doesn't 'disallow-in'). We opt for // 'disallow-in' set to 'false'. Otherwise, if we had 'allowsIn' set to 'true', then almost // all nodes would need extra state on them to store this info. // @@ -1030,20 +1030,20 @@ module ts { // EqualityExpression[?In, ?Yield] === RelationalExpression[?In, ?Yield] // EqualityExpression[?In, ?Yield] !== RelationalExpression[?In, ?Yield] // - // Where you have to be careful is then understanding what the points are in the grammar + // Where you have to be careful is then understanding what the points are in the grammar // where the values are *not* passed along. For example: // // SingleNameBinding[Yield,GeneratorParameter] // [+GeneratorParameter]BindingIdentifier[Yield] Initializer[In]opt // [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt // - // Here this is saying that if the GeneratorParameter context flag is set, that we should + // Here this is saying that if the GeneratorParameter context flag is set, that we should // explicitly set the 'yield' context flag to false before calling into the BindingIdentifier // and we should explicitly unset the 'yield' context flag before calling into the Initializer. - // production. Conversely, if the GeneratorParameter context flag is not set, then we + // production. Conversely, if the GeneratorParameter context flag is not set, then we // should leave the 'yield' context flag alone. // - // Getting this all correct is tricky and requires careful reading of the grammar to + // Getting this all correct is tricky and requires careful reading of the grammar to // understand when these values should be changed versus when they should be inherited. // // Note: it should not be necessary to save/restore these flags during speculative/lookahead @@ -1051,7 +1051,7 @@ module ts { // descent parsing and unwinding. let contextFlags: ParserContextFlags = 0; - // Whether or not we've had a parse error since creating the last AST node. If we have + // Whether or not we've had a parse error since creating the last AST node. If we have // encountered an error, it will be stored on the next AST node we create. Parse errors // can be broken down into three categories: // @@ -1062,7 +1062,7 @@ module ts { // by the 'parseExpected' function. // // 3) A token was present that no parsing function was able to consume. This type of error - // only occurs in the 'abortParsingListOrMoveToNextToken' function when the parser + // only occurs in the 'abortParsingListOrMoveToNextToken' function when the parser // decides to skip the token. // // In all of these cases, we want to mark the next node as having had an error before it. @@ -1071,8 +1071,8 @@ module ts { // node. in that event we would then not produce the same errors as we did before, causing // significant confusion problems. // - // Note: it is necessary that this value be saved/restored during speculative/lookahead - // parsing. During lookahead parsing, we will often create a node. That node will have + // Note: it is necessary that this value be saved/restored during speculative/lookahead + // parsing. During lookahead parsing, we will often create a node. That node will have // this value attached, and then this value will be set back to 'false'. If we decide to // rewind, we must get back to the same value we had prior to the lookahead. // @@ -1135,7 +1135,7 @@ module ts { setDisallowInContext(true); return result; } - + // no need to do anything special if 'in' is already allowed. return func(); } @@ -1206,7 +1206,7 @@ module ts { sourceFile.parseDiagnostics.push(createFileDiagnostic(sourceFile, start, length, message, arg0)); } - // Mark that we've encountered an error. We'll set an appropriate bit on the next + // Mark that we've encountered an error. We'll set an appropriate bit on the next // node we finish so that it can't be reused incrementally. parseErrorBeforeNextFinishedNode = true; } @@ -1245,7 +1245,7 @@ module ts { } function speculationHelper(callback: () => T, isLookAhead: boolean): T { - // Keep track of the state we'll need to rollback to if lookahead fails (or if the + // Keep track of the state we'll need to rollback to if lookahead fails (or if the // caller asked us to always reset our state). let saveToken = token; let saveParseDiagnosticsLength = sourceFile.parseDiagnostics.length; @@ -1253,13 +1253,13 @@ module ts { // Note: it is not actually necessary to save/restore the context flags here. That's // because the saving/restorating of these flags happens naturally through the recursive - // descent nature of our parser. However, we still store this here just so we can + // descent nature of our parser. However, we still store this here just so we can // assert that that invariant holds. let saveContextFlags = contextFlags; // If we're only looking ahead, then tell the scanner to only lookahead as well. - // Otherwise, if we're actually speculatively parsing, then tell the scanner to do the - // same. + // Otherwise, if we're actually speculatively parsing, then tell the scanner to do the + // same. let result = isLookAhead ? scanner.lookAhead(callback) : scanner.tryScan(callback); @@ -1277,15 +1277,15 @@ module ts { return result; } - // Invokes the provided callback then unconditionally restores the parser to the state it + // Invokes the provided callback then unconditionally restores the parser to the state it // was in immediately prior to invoking the callback. The result of invoking the callback // is returned from this function. function lookAhead(callback: () => T): T { return speculationHelper(callback, /*isLookAhead:*/ true); } - + // Invokes the provided callback. If the callback returns something falsy, then it restores - // the parser to the state it was in immediately prior to invoking the callback. If the + // the parser to the state it was in immediately prior to invoking the callback. If the // callback returns something truthy, then the parser state is not rolled back. The result // of invoking the callback is returned from this function. function tryParse(callback: () => T): T { @@ -1296,8 +1296,8 @@ module ts { if (token === SyntaxKind.Identifier) { return true; } - - // If we have a 'yield' keyword, and we're in the [yield] context, then 'yield' is + + // If we have a 'yield' keyword, and we're in the [yield] context, then 'yield' is // considered a keyword and is not an identifier. if (token === SyntaxKind.YieldKeyword && inYieldContext()) { return false; @@ -1464,7 +1464,7 @@ module ts { // LiteralPropertyName // [+GeneratorParameter] ComputedPropertyName // [~GeneratorParameter] ComputedPropertyName[?Yield] - // + // // ComputedPropertyName[Yield] : // [ AssignmentExpression[In, ?Yield] ] // @@ -1648,13 +1648,13 @@ module ts { } function isVariableDeclaratorListTerminator(): boolean { - // If we can consume a semicolon (either explicitly, or with ASI), then consider us done + // If we can consume a semicolon (either explicitly, or with ASI), then consider us done // with parsing the list of variable declarators. if (canParseSemicolon()) { return true; } - // in the case where we're parsing the variable declarator of a 'for-in' statement, we + // in the case where we're parsing the variable declarator of a 'for-in' statement, we // are done if we see an 'in' keyword in front of us. Same with for-of if (isInOrOfKeyword(token)) { return true; @@ -1730,7 +1730,7 @@ module ts { if (node) { return consumeNode(node); } - + return parseElement(); } @@ -1738,9 +1738,9 @@ module ts { // If there is an outstanding parse error that we've encountered, but not attached to // some node, then we cannot get a node from the old source tree. This is because we // want to mark the next node we encounter as being unusable. - // + // // Note: This may be too conservative. Perhaps we could reuse hte node and set the bit - // on it (or its leftmost child) as having the error. For now though, being conservative + // on it (or its leftmost child) as having the error. For now though, being conservative // is nice and likely won't ever affect perf. if (parseErrorBeforeNextFinishedNode) { return undefined; @@ -1763,18 +1763,18 @@ module ts { return undefined; } - // Can't reuse a node that contains a parse error. This is necessary so that we + // Can't reuse a node that contains a parse error. This is necessary so that we // produce the same set of errors again. if (containsParseError(node)) { return undefined; } - // We can only reuse a node if it was parsed under the same strict mode that we're + // We can only reuse a node if it was parsed under the same strict mode that we're // currently in. i.e. if we originally parsed a node in non-strict mode, but then // the user added 'using strict' at the top of the file, then we can't use that node // again as the presense of strict mode may cause us to parse the tokens in the file // differetly. - // + // // Note: we *can* reuse tokens when the strict mode changes. That's because tokens // are unaffected by strict mode. It's just the parser will decide what to do with it // differently depending on what mode it is in. @@ -1828,32 +1828,32 @@ module ts { case ParsingContext.Parameters: return isReusableParameter(node); - // Any other lists we do not care about reusing nodes in. But feel free to add if + // Any other lists we do not care about reusing nodes in. But feel free to add if // you can do so safely. Danger areas involve nodes that may involve speculative // parsing. If speculative parsing is involved with the node, then the range the // parser reached while looking ahead might be in the edited range (see the example // in canReuseVariableDeclaratorNode for a good case of this). case ParsingContext.HeritageClauses: - // This would probably be safe to reuse. There is no speculative parsing with + // This would probably be safe to reuse. There is no speculative parsing with // heritage clauses. case ParsingContext.TypeReferences: - // This would probably be safe to reuse. There is no speculative parsing with + // This would probably be safe to reuse. There is no speculative parsing with // type names in a heritage clause. There can be generic names in the type - // name list. But because it is a type context, we never use speculative + // name list. But because it is a type context, we never use speculative // parsing on the type argument list. case ParsingContext.TypeParameters: - // This would probably be safe to reuse. There is no speculative parsing with + // This would probably be safe to reuse. There is no speculative parsing with // type parameters. Note that that's because type *parameters* only occur in // unambiguous *type* contexts. While type *arguments* occur in very ambiguous // *expression* contexts. case ParsingContext.TupleElementTypes: - // This would probably be safe to reuse. There is no speculative parsing with + // This would probably be safe to reuse. There is no speculative parsing with // tuple types. - // Technically, type argument list types are probably safe to reuse. While + // Technically, type argument list types are probably safe to reuse. While // speculative parsing is involved with them (since type argument lists are only // produced from speculative parsing a < as a type argument list), we only have // the types because speculative parsing succeeded. Thus, the lookahead never @@ -1861,12 +1861,12 @@ module ts { case ParsingContext.TypeArguments: // Note: these are almost certainly not safe to ever reuse. Expressions commonly - // need a large amount of lookahead, and we should not reuse them as they may + // need a large amount of lookahead, and we should not reuse them as they may // have actually intersected the edit. case ParsingContext.ArgumentExpressions: // This is not safe to reuse for the same reason as the 'AssignmentExpression' - // cases. i.e. a property assignment may end with an expression, and thus might + // cases. i.e. a property assignment may end with an expression, and thus might // have lookahead far beyond it's old node. case ParsingContext.ObjectLiteralMembers: } @@ -1980,12 +1980,12 @@ module ts { // // let v = new List < A, B // - // This is actually legal code. It's a list of variable declarators "v = new List() - // - // then we have a problem. "v = new ListcreateMissingNode(SyntaxKind.Identifier, /*reportAtCurrentToken:*/ true, Diagnostics.Identifier_expected); } @@ -2185,7 +2185,7 @@ module ts { if (scanner.hasExtendedUnicodeEscape()) { node.hasExtendedUnicodeEscape = true; } - + if (scanner.isUnterminated()) { node.isUnterminated = true; } @@ -2193,7 +2193,7 @@ module ts { let tokenPos = scanner.getTokenPos(); nextToken(); finishNode(node); - + // Octal literals are not allowed in strict mode or ES5 // Note that theoretically the following condition would hold true literals like 009, // which is not octal.But because of how the scanner separates the tokens, we would @@ -2232,7 +2232,7 @@ module ts { let node = createNode(SyntaxKind.TypeParameter); node.name = parseIdentifier(); if (parseOptional(SyntaxKind.ExtendsKeyword)) { - // It's not uncommon for people to write improper constraints to a generic. If the + // It's not uncommon for people to write improper constraints to a generic. If the // user writes a constraint that is an expression and not an actual type, then parse // it out as an expression (so we can recover well), but report that a type is needed // instead. @@ -2294,7 +2294,7 @@ module ts { if (getFullWidth(node.name) === 0 && node.flags === 0 && isModifier(token)) { // in cases like - // 'use strict' + // 'use strict' // function foo(static) // isParameter('static') === true, because of isModifier('static') // however 'static' is not a legal identifier in a strict mode. @@ -2341,7 +2341,7 @@ module ts { } } - // Note: after careful analysis of the grammar, it does not appear to be possible to + // Note: after careful analysis of the grammar, it does not appear to be possible to // have 'Yield' And 'GeneratorParameter' not in sync. i.e. any production calling // this FormalParameters production either always sets both to true, or always sets // both to false. As such we only have a single parameter to represent both. @@ -2388,7 +2388,7 @@ module ts { } function parseTypeMemberSemicolon() { - // We allow type members to be separated by commas or (possibly ASI) semicolons. + // We allow type members to be separated by commas or (possibly ASI) semicolons. // First check if it was a comma. If so, we're done with the member. if (parseOptional(SyntaxKind.CommaToken)) { return; @@ -2561,9 +2561,9 @@ module ts { case SyntaxKind.NumericLiteral: return parsePropertyOrMethodSignature(); default: - // Index declaration as allowed as a type member. But as per the grammar, + // Index declaration as allowed as a type member. But as per the grammar, // they also allow modifiers. So we have to check for an index declaration - // that might be following modifiers. This ensures that things work properly + // that might be following modifiers. This ensures that things work properly // when incrementally parsing as the parser will produce the Index declaration // if it has the same text regardless of whether it is inside a class or an // object type. @@ -2844,7 +2844,7 @@ module ts { function parseExpression(): Expression { // Expression[in]: - // AssignmentExpression[in] + // AssignmentExpression[in] // Expression[in] , AssignmentExpression[in] let expr = parseAssignmentExpressionOrHigher(); @@ -2860,13 +2860,13 @@ module ts { // It's not uncommon during typing for the user to miss writing the '=' token. Check if // there is no newline after the last token and if we're on an expression. If so, parse // this as an equals-value clause with a missing equals. - // NOTE: There are two places where we allow equals-value clauses. The first is in a + // NOTE: There are two places where we allow equals-value clauses. The first is in a // variable declarator. The second is with a parameter. For variable declarators // it's more likely that a { would be a allowed (as an object literal). While this // is also allowed for parameters, the risk is that we consume the { as an object // literal when it really will be for the block following the parameter. if (scanner.hasPrecedingLineBreak() || (inParameter && token === SyntaxKind.OpenBraceToken) || !isStartOfExpression()) { - // preceding line break, open brace in a parameter (likely a function body) or current token is not an expression - + // preceding line break, open brace in a parameter (likely a function body) or current token is not an expression - // do not try to parse initializer return undefined; } @@ -2887,17 +2887,17 @@ module ts { // 4) ArrowFunctionExpression[?in,?yield] // 5) [+Yield] YieldExpression[?In] // - // Note: for ease of implementation we treat productions '2' and '3' as the same thing. + // Note: for ease of implementation we treat productions '2' and '3' as the same thing. // (i.e. they're both BinaryExpressions with an assignment operator in it). // First, do the simple check if we have a YieldExpression (production '5'). if (isYieldExpression()) { return parseYieldExpression(); - } + } // Then, check if we have an arrow function (production '4') that starts with a parenthesized // parameter list. If we do, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is - // not a LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done + // not a LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done // with AssignmentExpression if we see one. let arrowExpression = tryParseParenthesizedArrowFunctionExpression(); if (arrowExpression) { @@ -2908,9 +2908,9 @@ module ts { // start with a LogicalOrExpression, while the assignment productions can only start with // LeftHandSideExpressions. // - // So, first, we try to just parse out a BinaryExpression. If we get something that is a - // LeftHandSide or higher, then we can try to parse out the assignment expression part. - // Otherwise, we try to parse out the conditional expression bit. We want to allow any + // So, first, we try to just parse out a BinaryExpression. If we get something that is a + // LeftHandSide or higher, then we can try to parse out the assignment expression part. + // Otherwise, we try to parse out the conditional expression bit. We want to allow any // binary expression here, so we pass in the 'lowest' precedence here so that it matches // and consumes anything. let expr = parseBinaryExpressionOrHigher(/*precedence:*/ 0); @@ -2918,12 +2918,12 @@ module ts { // To avoid a look-ahead, we did not handle the case of an arrow function with a single un-parenthesized // parameter ('x => ...') above. We handle it here by checking if the parsed expression was a single // identifier and the current token is an arrow. - if (expr.kind === SyntaxKind.Identifier && token === SyntaxKind.EqualsGreaterThanToken) { + if (expr.kind === SyntaxKind.Identifier && token === SyntaxKind.EqualsGreaterThanToken && !scanner.hasPrecedingLineBreak()) { return parseSimpleArrowFunctionExpression(expr); } // Now see if we might be in cases '2' or '3'. - // If the expression was a LHS expression, and we have an assignment operator, then + // If the expression was a LHS expression, and we have an assignment operator, then // we're in '2' or '3'. Consume the assignment and return. // // Note: we call reScanGreaterToken so that we get an appropriately merged token @@ -2938,7 +2938,7 @@ module ts { function isYieldExpression(): boolean { if (token === SyntaxKind.YieldKeyword) { - // If we have a 'yield' keyword, and htis is a context where yield expressions are + // If we have a 'yield' keyword, and htis is a context where yield expressions are // allowed, then definitely parse out a yield expression. if (inYieldContext()) { return true; @@ -2953,12 +2953,12 @@ module ts { // We're in a context where 'yield expr' is not allowed. However, if we can // definitely tell that the user was trying to parse a 'yield expr' and not // just a normal expr that start with a 'yield' identifier, then parse out - // a 'yield expr'. We can then report an error later that they are only + // a 'yield expr'. We can then report an error later that they are only // allowed in generator expressions. - // + // // for example, if we see 'yield(foo)', then we'll have to treat that as an // invocation expression of something called 'yield'. However, if we have - // 'yield foo' then that is not legal as a normal expression, so we can + // 'yield foo' then that is not legal as a normal expression, so we can // definitely recognize this as a yield expression. // // for now we just check if the next token is an identifier. More heuristics @@ -2997,7 +2997,7 @@ module ts { return finishNode(node); } else { - // if the next token is not on the same line as yield. or we don't have an '*' or + // if the next token is not on the same line as yield. or we don't have an '*' or // the start of an expressin, then this is just a simple "yield" expression. return finishNode(node); } @@ -3043,7 +3043,7 @@ module ts { return undefined; } - // If we have an arrow, then try to parse the body. Even if not, try to parse if we + // If we have an arrow, then try to parse the body. Even if not, try to parse if we // have an opening brace, just in case we're in an error state. if (parseExpected(SyntaxKind.EqualsGreaterThanToken) || token === SyntaxKind.OpenBraceToken) { arrowFunction.body = parseArrowFunctionExpressionBody(); @@ -3146,7 +3146,7 @@ module ts { // If we're speculatively parsing a signature for a parenthesized arrow function, then // we have to have a complete parameter list. Otherwise we might see something like // a => (b => c) - // And think that "(b =>" was actually a parenthesized arrow function with a missing + // And think that "(b =>" was actually a parenthesized arrow function with a missing // close paren. fillSignature(SyntaxKind.ColonToken, /*yieldAndGeneratorParameterContext:*/ false, /*requireCompleteParameterList:*/ !allowAmbiguity, node); @@ -3168,6 +3168,11 @@ module ts { return undefined; } + // Must be no line terminator before token `=>`. + if (scanner.hasPrecedingLineBreak()) { + return undefined; + } + return node; } @@ -3179,7 +3184,7 @@ module ts { if (isStartOfStatement(/*inErrorRecovery:*/ true) && !isStartOfExpressionStatement() && token !== SyntaxKind.FunctionKeyword) { // Check if we got a plain statement (i.e. no expression-statements, no functions expressions/declarations) // - // Here we try to recover from a potential error situation in the case where the + // Here we try to recover from a potential error situation in the case where the // user meant to supply a block. For example, if the user wrote: // // a => @@ -3204,10 +3209,10 @@ module ts { return leftOperand; } - // Note: we explicitly 'allowIn' in the whenTrue part of the condition expression, and - // we do not that for the 'whenFalse' part. + // Note: we explicitly 'allowIn' in the whenTrue part of the condition expression, and + // we do not that for the 'whenFalse' part. let node = createNode(SyntaxKind.ConditionalExpression, leftOperand.pos); - node.condition = leftOperand; + node.condition = leftOperand; node.questionToken = questionToken; node.whenTrue = allowInAnd(parseAssignmentExpressionOrHigher); node.colonToken = parseExpectedToken(SyntaxKind.ColonToken, /*reportAtCurrentPosition:*/ false, @@ -3227,7 +3232,7 @@ module ts { function parseBinaryExpressionRest(precedence: number, leftOperand: Expression): Expression { while (true) { - // We either have a binary operator here, or we're finished. We call + // We either have a binary operator here, or we're finished. We call // reScanGreaterToken so that we merge token sequences like > and = into >= reScanGreaterToken(); @@ -3374,15 +3379,15 @@ module ts { function parseLeftHandSideExpressionOrHigher(): LeftHandSideExpression { // Original Ecma: - // LeftHandSideExpression: See 11.2 + // LeftHandSideExpression: See 11.2 // NewExpression - // CallExpression + // CallExpression // // Our simplification: // - // LeftHandSideExpression: See 11.2 - // MemberExpression - // CallExpression + // LeftHandSideExpression: See 11.2 + // MemberExpression + // CallExpression // // See comment in parseMemberExpressionOrHigher on how we replaced NewExpression with // MemberExpression to make our lives easier. @@ -3391,14 +3396,14 @@ module ts { // out into its own productions: // // CallExpression: - // MemberExpression Arguments + // MemberExpression Arguments // CallExpression Arguments // CallExpression[Expression] // CallExpression.IdentifierName // super ( ArgumentListopt ) // super.IdentifierName // - // Because of the recursion in these calls, we need to bottom out first. There are two + // Because of the recursion in these calls, we need to bottom out first. There are two // bottom out states we can run into. Either we see 'super' which must start either of // the last two CallExpression productions. Or we have a MemberExpression which either // completes the LeftHandSideExpression, or starts the beginning of the first four @@ -3407,7 +3412,7 @@ module ts { ? parseSuperExpression() : parseMemberExpressionOrHigher(); - // Now, we *may* be complete. However, we might have consumed the start of a + // Now, we *may* be complete. However, we might have consumed the start of a // CallExpression. As such, we need to consume the rest of it here to be complete. return parseCallExpressionRest(expression); } @@ -3417,39 +3422,39 @@ module ts { // place ObjectCreationExpression and FunctionExpression into PrimaryExpression. // like so: // - // PrimaryExpression : See 11.1 + // PrimaryExpression : See 11.1 // this // Identifier // Literal // ArrayLiteral // ObjectLiteral - // (Expression) + // (Expression) // FunctionExpression // new MemberExpression Arguments? // - // MemberExpression : See 11.2 - // PrimaryExpression + // MemberExpression : See 11.2 + // PrimaryExpression // MemberExpression[Expression] // MemberExpression.IdentifierName // - // CallExpression : See 11.2 - // MemberExpression + // CallExpression : See 11.2 + // MemberExpression // CallExpression Arguments // CallExpression[Expression] - // CallExpression.IdentifierName + // CallExpression.IdentifierName // // Technically this is ambiguous. i.e. CallExpression defines: // // CallExpression: // CallExpression Arguments - // + // // If you see: "new Foo()" // - // Then that could be treated as a single ObjectCreationExpression, or it could be + // Then that could be treated as a single ObjectCreationExpression, or it could be // treated as the invocation of "new Foo". We disambiguate that in code (to match // the original grammar) by making sure that if we see an ObjectCreationExpression // we always consume arguments if they are there. So we treat "new Foo()" as an - // object creation only, and not at all as an invocation) Another way to think + // object creation only, and not at all as an invocation) Another way to think // about this is that for every "new" that we see, we will consume an argument list if // it is there as part of the *associated* object creation node. Any additional // argument lists we see, will become invocation expressions. @@ -3539,7 +3544,7 @@ module ts { if (token === SyntaxKind.LessThanToken) { // See if this is the start of a generic invocation. If so, consume it and - // keep checking for postfix expressions. Otherwise, it's just a '<' that's + // keep checking for postfix expressions. Otherwise, it's just a '<' that's // part of an arithmetic expression. Break out so we consume it higher in the // stack. let typeArguments = tryParse(parseTypeArgumentsInExpression); @@ -3593,8 +3598,8 @@ module ts { function canFollowTypeArgumentsInExpression(): boolean { switch (token) { - case SyntaxKind.OpenParenToken: // foo( - // this case are the only case where this token can legally follow a type argument + case SyntaxKind.OpenParenToken: // foo( + // this case are the only case where this token can legally follow a type argument // list. So we definitely want to treat this as a type arg list. case SyntaxKind.DotToken: // foo. @@ -3615,7 +3620,7 @@ module ts { case SyntaxKind.BarToken: // foo | case SyntaxKind.CloseBraceToken: // foo } case SyntaxKind.EndOfFileToken: // foo - // these cases can't legally follow a type arg list. However, they're not legal + // these cases can't legally follow a type arg list. However, they're not legal // expressions either. The user is probably in the middle of a generic type. So // treat it as such. return true; @@ -3836,7 +3841,7 @@ module ts { parseExpected(SyntaxKind.CloseParenToken); // From: https://mail.mozilla.org/pipermail/es-discuss/2011-August/016188.html - // 157 min --- All allen at wirfs-brock.com CONF --- "do{;}while(false)false" prohibited in + // 157 min --- All allen at wirfs-brock.com CONF --- "do{;}while(false)false" prohibited in // spec but allowed in consensus reality. Approved -- this is the de-facto standard whereby // do;while(0)x will have a semicolon inserted before x. parseOptional(SyntaxKind.SemicolonToken); @@ -3974,9 +3979,9 @@ module ts { // ThrowStatement[Yield] : // throw [no LineTerminator here]Expression[In, ?Yield]; - // Because of automatic semicolon insertion, we need to report error if this + // Because of automatic semicolon insertion, we need to report error if this // throw could be terminated with a semicolon. Note: we can't call 'parseExpression' - // directly as that might consume an expression on the following line. + // directly as that might consume an expression on the following line. // We just return 'undefined' in that case. The actual error will be reported in the // grammar walker. let node = createNode(SyntaxKind.ThrowStatement); @@ -4046,9 +4051,9 @@ module ts { function isStartOfStatement(inErrorRecovery: boolean): boolean { // Functions and variable statements are allowed as a statement. But as per the grammar, - // they also allow modifiers. So we have to check for those statements that might be - // following modifiers.This ensures that things work properly when incrementally parsing - // as the parser will produce the same FunctionDeclaraiton or VariableStatement if it has + // they also allow modifiers. So we have to check for those statements that might be + // following modifiers.This ensures that things work properly when incrementally parsing + // as the parser will produce the same FunctionDeclaraiton or VariableStatement if it has // the same text regardless of whether it is inside a block or not. if (isModifier(token)) { let result = lookAhead(parseVariableStatementOrFunctionDeclarationWithModifiers); @@ -4134,7 +4139,7 @@ module ts { return parseBlock(/*ignoreMissingOpenBrace:*/ false, /*checkForStrictMode:*/ false); case SyntaxKind.VarKeyword: case SyntaxKind.ConstKeyword: - // const here should always be parsed as const declaration because of check in 'isStatement' + // const here should always be parsed as const declaration because of check in 'isStatement' return parseVariableStatement(scanner.getStartPos(), /*modifiers:*/ undefined); case SyntaxKind.FunctionKeyword: return parseFunctionDeclaration(scanner.getStartPos(), /*modifiers:*/ undefined); @@ -4174,8 +4179,8 @@ module ts { } // Else parse it like identifier - fall through default: - // Functions and variable statements are allowed as a statement. But as per - // the grammar, they also allow modifiers. So we have to check for those + // Functions and variable statements are allowed as a statement. But as per + // the grammar, they also allow modifiers. So we have to check for those // statements that might be following modifiers. This ensures that things // work properly when incrementally parsing as the parser will produce the // same FunctionDeclaraiton or VariableStatement if it has the same text @@ -4336,7 +4341,7 @@ module ts { return finishNode(node); } - + function canFollowContextualOfKeyword(): boolean { return nextTokenIsIdentifier() && nextToken() === SyntaxKind.CloseParenToken; } @@ -4439,7 +4444,7 @@ module ts { if (token === SyntaxKind.OpenBracketToken) { return true; } - + // If we were able to get any potential identifier... if (idToken !== undefined) { // If we have a non-keyword identifier, or if we have an accessor, then it's safe to parse. @@ -4718,7 +4723,7 @@ module ts { // import ImportClause from ModuleSpecifier ; // import ModuleSpecifier; if (identifier || // import id - token === SyntaxKind.AsteriskToken || // import * + token === SyntaxKind.AsteriskToken || // import * token === SyntaxKind.OpenBraceToken) { // import { importDeclaration.importClause = parseImportClause(identifier, afterImportPos); parseExpected(SyntaxKind.FromKeyword); @@ -4744,7 +4749,7 @@ module ts { importClause.name = identifier; } - // If there was no default import or if there is comma token after default import + // If there was no default import or if there is comma token after default import // parse namespace or named imports if (!importClause.name || parseOptional(SyntaxKind.CommaToken)) { @@ -4770,12 +4775,12 @@ module ts { } function parseModuleSpecifier(): Expression { - // We allow arbitrary expressions here, even though the grammar only allows string + // We allow arbitrary expressions here, even though the grammar only allows string // literals. We check to ensure that it is only a string literal later in the grammar // walker. let result = parseExpression(); - // Ensure the string being required is in our 'identifier' table. This will ensure - // that features like 'find refs' will look inside this file when search for its name. + // Ensure the string being required is in our 'identifier' table. This will ensure + // that features like 'find refs' will look inside this file when search for its name. if (result.kind === SyntaxKind.StringLiteral) { internIdentifier((result).text); } @@ -5013,8 +5018,8 @@ module ts { let amdDependencies: {path: string; name: string}[] = []; let amdModuleName: string; - // Keep scanning all the leading trivia in the file until we get to something that - // isn't trivia. Any single line comment will be analyzed to see if it is a + // Keep scanning all the leading trivia in the file until we get to something that + // isn't trivia. Any single line comment will be analyzed to see if it is a // reference comment. while (true) { let kind = triviaScanner.scan(); diff --git a/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt b/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt new file mode 100644 index 0000000000000..0450903f7174c --- /dev/null +++ b/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt @@ -0,0 +1,70 @@ +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(2,5): error TS1109: Expression expected. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(4,7): error TS1109: Expression expected. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(6,5): error TS1109: Expression expected. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(8,7): error TS1109: Expression expected. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(10,5): error TS1109: Expression expected. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(12,7): error TS1109: Expression expected. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(14,5): error TS1109: Expression expected. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(16,7): error TS1109: Expression expected. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(19,1): error TS2346: Supplied parameters do not match any signature of call target. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(20,5): error TS1109: Expression expected. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(21,1): error TS2346: Supplied parameters do not match any signature of call target. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(22,5): error TS1109: Expression expected. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(22,17): error TS1005: ':' expected. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(22,22): error TS1005: ',' expected. + + +==== tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts (14 errors) ==== + var f1 = () + => { } + ~~ +!!! error TS1109: Expression expected. + var f2 = (x: string, y: string) /* + */ => { } + ~~ +!!! error TS1109: Expression expected. + var f3 = (x: string, y: number, ...rest) + => { } + ~~ +!!! error TS1109: Expression expected. + var f4 = (x: string, y: number, ...rest) /* + */ => { } + ~~ +!!! error TS1109: Expression expected. + var f5 = (...rest) + => { } + ~~ +!!! error TS1109: Expression expected. + var f6 = (...rest) /* + */ => { } + ~~ +!!! error TS1109: Expression expected. + var f7 = (x: string, y: number, z = 10) + => { } + ~~ +!!! error TS1109: Expression expected. + var f8 = (x: string, y: number, z = 10) /* + */ => { } + ~~ +!!! error TS1109: Expression expected. + + function foo(func: () => boolean) { } + foo(() + ~~~~~~ + => true); + ~~~~~~~~~~~~ +!!! error TS2346: Supplied parameters do not match any signature of call target. + ~~ +!!! error TS1109: Expression expected. + foo(() + ~~~~~~ + => { return false; }); + ~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2346: Supplied parameters do not match any signature of call target. + ~~ +!!! error TS1109: Expression expected. + ~~~~~ +!!! error TS1005: ':' expected. + ~ +!!! error TS1005: ',' expected. + \ No newline at end of file diff --git a/tests/baselines/reference/disallowLineTerminatorBeforeArrow.js b/tests/baselines/reference/disallowLineTerminatorBeforeArrow.js new file mode 100644 index 0000000000000..c98b6a89d4f16 --- /dev/null +++ b/tests/baselines/reference/disallowLineTerminatorBeforeArrow.js @@ -0,0 +1,60 @@ +//// [disallowLineTerminatorBeforeArrow.ts] +var f1 = () + => { } +var f2 = (x: string, y: string) /* + */ => { } +var f3 = (x: string, y: number, ...rest) + => { } +var f4 = (x: string, y: number, ...rest) /* + */ => { } +var f5 = (...rest) + => { } +var f6 = (...rest) /* + */ => { } +var f7 = (x: string, y: number, z = 10) + => { } +var f8 = (x: string, y: number, z = 10) /* + */ => { } + +function foo(func: () => boolean) { } +foo(() + => true); +foo(() + => { return false; }); + + +//// [disallowLineTerminatorBeforeArrow.js] +var f1 = ; +{ +} +var f2 = ; /* + */ +{ +} +var f3 = ; +{ +} +var f4 = ; /* + */ +{ +} +var f5 = ; +{ +} +var f6 = ; /* + */ +{ +} +var f7 = ; +{ +} +var f8 = ; /* + */ +{ +} +function foo(func) { +} +foo(, true); +foo(, { + return: false +}); diff --git a/tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts b/tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts new file mode 100644 index 0000000000000..316ff92c56c12 --- /dev/null +++ b/tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts @@ -0,0 +1,22 @@ +var f1 = () + => { } +var f2 = (x: string, y: string) /* + */ => { } +var f3 = (x: string, y: number, ...rest) + => { } +var f4 = (x: string, y: number, ...rest) /* + */ => { } +var f5 = (...rest) + => { } +var f6 = (...rest) /* + */ => { } +var f7 = (x: string, y: number, z = 10) + => { } +var f8 = (x: string, y: number, z = 10) /* + */ => { } + +function foo(func: () => boolean) { } +foo(() + => true); +foo(() + => { return false; }); From dd16fed21e5cf96e87a27ce25c5fe3bdb3ece9f0 Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Tue, 10 Mar 2015 17:11:25 -0400 Subject: [PATCH 02/10] Perform error reporting in checker --- src/compiler/checker.ts | 12 ++- .../diagnosticInformationMap.generated.ts | 1 + src/compiler/diagnosticMessages.json | 4 + src/compiler/parser.ts | 14 ++- src/compiler/types.ts | 44 +++++----- .../baselines/reference/APISample_compile.js | 3 + .../reference/APISample_compile.types | 7 ++ tests/baselines/reference/APISample_linter.js | 3 + .../reference/APISample_linter.types | 7 ++ .../reference/APISample_transform.js | 3 + .../reference/APISample_transform.types | 7 ++ .../baselines/reference/APISample_watcher.js | 3 + .../reference/APISample_watcher.types | 7 ++ ...sallowLineTerminatorBeforeArrow.errors.txt | 86 +++++++++---------- .../disallowLineTerminatorBeforeArrow.js | 70 ++++++++------- 15 files changed, 166 insertions(+), 105 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0dacb20ece41c..dae254253ca95 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11377,7 +11377,17 @@ module ts { function checkGrammarFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean { // Prevent cascading error by short-circuit - return checkGrammarModifiers(node) || checkGrammarTypeParameterList(node, node.typeParameters) || checkGrammarParameterList(node.parameters); + return checkGrammarModifiers(node) || checkGrammarTypeParameterList(node, node.typeParameters) || checkGrammarParameterList(node.parameters) || checkGrammarArrowFunction(node); + } + + function checkGrammarArrowFunction(node: FunctionLikeDeclaration): boolean { + if (node.kind === SyntaxKind.ArrowFunction) { + if ((node).lineTerminatorBeforeArrow) { + grammarErrorOnNode(node, Diagnostics.Line_terminator_not_permitted_before_arrow); + return true; + } + } + return false; } function checkGrammarIndexSignatureParameters(node: SignatureDeclaration): boolean { diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index d40fcd25ce089..556df1565b0f8 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -157,6 +157,7 @@ module ts { Catch_clause_variable_cannot_have_an_initializer: { code: 1197, category: DiagnosticCategory.Error, key: "Catch clause variable cannot have an initializer." }, An_extended_Unicode_escape_value_must_be_between_0x0_and_0x10FFFF_inclusive: { code: 1198, category: DiagnosticCategory.Error, key: "An extended Unicode escape value must be between 0x0 and 0x10FFFF inclusive." }, Unterminated_Unicode_escape_sequence: { code: 1199, category: DiagnosticCategory.Error, key: "Unterminated Unicode escape sequence." }, + Line_terminator_not_permitted_before_arrow: { code: 1200, category: DiagnosticCategory.Error, key: "Line terminator not permitted before arrow." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index c4121e92251b2..0c00d8c974ce1 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -619,6 +619,10 @@ "category": "Error", "code": 1199 }, + "Line terminator not permitted before arrow.": { + "category": "Error", + "code": 1200 + }, "Duplicate identifier '{0}'.": { "category": "Error", "code": 2300 diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index fc02c3f3eef3f..06655b1d822f3 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2918,7 +2918,7 @@ module ts { // To avoid a look-ahead, we did not handle the case of an arrow function with a single un-parenthesized // parameter ('x => ...') above. We handle it here by checking if the parsed expression was a single // identifier and the current token is an arrow. - if (expr.kind === SyntaxKind.Identifier && token === SyntaxKind.EqualsGreaterThanToken && !scanner.hasPrecedingLineBreak()) { + if (expr.kind === SyntaxKind.Identifier && token === SyntaxKind.EqualsGreaterThanToken) { return parseSimpleArrowFunctionExpression(expr); } @@ -3007,7 +3007,7 @@ module ts { Debug.assert(token === SyntaxKind.EqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>"); let node = createNode(SyntaxKind.ArrowFunction, identifier.pos); - + let parameter = createNode(SyntaxKind.Parameter, identifier.pos); parameter.name = identifier; finishNode(parameter); @@ -3016,6 +3016,7 @@ module ts { node.parameters.pos = parameter.pos; node.parameters.end = parameter.end; + node.lineTerminatorBeforeArrow = scanner.hasPrecedingLineBreak(); parseExpected(SyntaxKind.EqualsGreaterThanToken); node.body = parseArrowFunctionExpressionBody(); @@ -3140,8 +3141,8 @@ module ts { } function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): FunctionExpression { - let node = createNode(SyntaxKind.ArrowFunction); - // Arrow functions are never generators. + let node = createNode(SyntaxKind.ArrowFunction); + // Arrow functions are never generators. // // If we're speculatively parsing a signature for a parenthesized arrow function, then // we have to have a complete parameter list. Otherwise we might see something like @@ -3168,10 +3169,7 @@ module ts { return undefined; } - // Must be no line terminator before token `=>`. - if (scanner.hasPrecedingLineBreak()) { - return undefined; - } + node.lineTerminatorBeforeArrow = scanner.hasPrecedingLineBreak(); return node; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c43591911abd4..56820a10924f5 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -329,7 +329,7 @@ module ts { // If the parser encountered an error when parsing the code that created this node. Note // the parser only sets this directly on the node it creates right after encountering the - // error. + // error. ThisNodeHasError = 1 << 4, // Context flags set directly by the parser. @@ -337,7 +337,7 @@ module ts { // Context flags computed by aggregating child flags upwards. - // Used during incremental parsing to determine if this node or any of its children had an + // Used during incremental parsing to determine if this node or any of its children had an // error. Computed only once and then cached. ThisNodeOrAnySubNodesHasError = 1 << 5, @@ -354,7 +354,7 @@ module ts { export interface Node extends TextRange { kind: SyntaxKind; flags: NodeFlags; - // Specific context the parser was in when this node was created. Normally undefined. + // Specific context the parser was in when this node was created. Normally undefined. // Only set when the parser was in some interesting context (like async/yield). parserContextFlags?: ParserContextFlags; modifiers?: ModifiersArray; // Array of modifiers @@ -524,7 +524,7 @@ module ts { body?: Block; } - // See the comment on MethodDeclaration for the intuition behind AccessorDeclaration being a + // See the comment on MethodDeclaration for the intuition behind AccessorDeclaration being a // ClassElement and an ObjectLiteralElement. export interface AccessorDeclaration extends FunctionLikeDeclaration, ClassElement, ObjectLiteralElement { _accessorDeclarationBrand: any; @@ -575,12 +575,12 @@ module ts { export interface StringLiteralTypeNode extends LiteralExpression, TypeNode { } - // Note: 'brands' in our syntax nodes serve to give us a small amount of nominal typing. + // Note: 'brands' in our syntax nodes serve to give us a small amount of nominal typing. // Consider 'Expression'. Without the brand, 'Expression' is actually no different // (structurally) than 'Node'. Because of this you can pass any Node to a function that // takes an Expression without any error. By using the 'brands' we ensure that the type - // checker actually thinks you have something of the right type. Note: the brands are - // never actually given values. At runtime they have zero cost. + // checker actually thinks you have something of the right type. Note: the brands are + // never actually given values. At runtime they have zero cost. export interface Expression extends Node { _expressionBrand: any; @@ -653,6 +653,10 @@ module ts { body: Block | Expression; // Required, whereas the member inherited from FunctionDeclaration is optional } + export interface ArrowFunctionExpression extends FunctionExpression { + lineTerminatorBeforeArrow: boolean; + } + // The text property of a LiteralExpression stores the interpreted value of the literal in text form. For a StringLiteral, // or any literal of a template, this means quotes have been removed and escapes have been converted to actual characters. // For a NumericLiteral, the stored value is the toString() representation of the number. For example 1, 1.00, and 1e0 are all stored as just "1". @@ -735,7 +739,7 @@ module ts { } export interface VariableStatement extends Statement { - declarationList: VariableDeclarationList; + declarationList: VariableDeclarationList; } export interface ExpressionStatement extends Statement { @@ -903,7 +907,7 @@ module ts { moduleSpecifier: Expression; } - // In case of: + // In case of: // import d from "mod" => name = d, namedBinding = undefined // import * as ns from "mod" => name = undefined, namedBinding: NamespaceImport = { name: ns } // import d, * as ns from "mod" => name = d, namedBinding: NamespaceImport = { name: ns } @@ -969,7 +973,7 @@ module ts { externalModuleIndicator: Node; languageVersion: ScriptTarget; identifiers: Map; - + /* @internal */ nodeCount: number; /* @internal */ identifierCount: number; /* @internal */ symbolCount: number; @@ -977,10 +981,10 @@ module ts { // File level diagnostics reported by the parser (includes diagnostics about /// references // as well as code diagnostics). /* @internal */ parseDiagnostics: Diagnostic[]; - + // File level diagnostics reported by the binder. /* @internal */ bindDiagnostics: Diagnostic[]; - + // Stores a line map for the file. // This field should never be used directly to obtain line map, use getLineMap function instead. /* @internal */ lineMap: number[]; @@ -1000,10 +1004,10 @@ module ts { getSourceFiles(): SourceFile[]; /** - * Emits the javascript and declaration files. If targetSourceFile is not specified, then + * Emits the javascript and declaration files. If targetSourceFile is not specified, then * the javascript and declaration files will be produced for all the files in this program. * If targetSourceFile is specified, then only the javascript and declaration for that - * specific file will be generated. + * specific file will be generated. * * If writeFile is not specified then the writeFile callback from the compiler host will be * used for writing the javascript and declaration files. Otherwise, the writeFile parameter @@ -1021,7 +1025,7 @@ module ts { getCommonSourceDirectory(): string; - // For testing purposes only. Should not be used by any other consumers (including the + // For testing purposes only. Should not be used by any other consumers (including the // language service). /* @internal */ getDiagnosticsProducingTypeChecker(): TypeChecker; @@ -1058,7 +1062,7 @@ module ts { // when -version or -help was provided, or this was a normal compilation, no diagnostics // were produced, and all outputs were generated successfully. Success = 0, - + // Diagnostics were produced and because of them no code was generated. DiagnosticsPresent_OutputsSkipped = 1, @@ -1168,12 +1172,12 @@ module ts { // Write symbols's type argument if it is instantiated symbol // eg. class C { p: T } <-- Show p as C.p here - // var a: C; + // var a: C; // var p = a.p; <--- Here p is property of C so show it as C.p instead of just C.p - WriteTypeParametersOrArguments = 0x00000001, + WriteTypeParametersOrArguments = 0x00000001, // Use only external alias information to get the symbol name in the given context - // eg. module m { export class c { } } import x = m.c; + // eg. module m { export class c { } } import x = m.c; // When this flag is specified m.c will be used to refer to the class instead of alias symbol x UseOnlyExternalAliasing = 0x00000002, } @@ -1778,7 +1782,7 @@ module ts { // Gets a count of how many times this collection has been modified. This value changes // each time 'add' is called (regardless of whether or not an equivalent diagnostic was // already in the collection). As such, it can be used as a simple way to tell if any - // operation caused diagnostics to be returned by storing and comparing the return value + // operation caused diagnostics to be returned by storing and comparing the return value // of this method before/after the operation is performed. getModificationCount(): number; } diff --git a/tests/baselines/reference/APISample_compile.js b/tests/baselines/reference/APISample_compile.js index 985718231810c..316649a35c978 100644 --- a/tests/baselines/reference/APISample_compile.js +++ b/tests/baselines/reference/APISample_compile.js @@ -553,6 +553,9 @@ declare module "typescript" { name?: Identifier; body: Block | Expression; } + interface ArrowFunctionExpression extends FunctionExpression { + lineTerminatorBeforeArrow: boolean; + } interface LiteralExpression extends PrimaryExpression { text: string; isUnterminated?: boolean; diff --git a/tests/baselines/reference/APISample_compile.types b/tests/baselines/reference/APISample_compile.types index 087c0389d0fce..bf51bb946c015 100644 --- a/tests/baselines/reference/APISample_compile.types +++ b/tests/baselines/reference/APISample_compile.types @@ -1668,6 +1668,13 @@ declare module "typescript" { >body : Expression | Block >Block : Block >Expression : Expression + } + interface ArrowFunctionExpression extends FunctionExpression { +>ArrowFunctionExpression : ArrowFunctionExpression +>FunctionExpression : FunctionExpression + + lineTerminatorBeforeArrow: boolean; +>lineTerminatorBeforeArrow : boolean } interface LiteralExpression extends PrimaryExpression { >LiteralExpression : LiteralExpression diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index d43d622007210..5f7dc308820c8 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -584,6 +584,9 @@ declare module "typescript" { name?: Identifier; body: Block | Expression; } + interface ArrowFunctionExpression extends FunctionExpression { + lineTerminatorBeforeArrow: boolean; + } interface LiteralExpression extends PrimaryExpression { text: string; isUnterminated?: boolean; diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index 14eb2936242bd..ede73749eb018 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -1814,6 +1814,13 @@ declare module "typescript" { >body : Expression | Block >Block : Block >Expression : Expression + } + interface ArrowFunctionExpression extends FunctionExpression { +>ArrowFunctionExpression : ArrowFunctionExpression +>FunctionExpression : FunctionExpression + + lineTerminatorBeforeArrow: boolean; +>lineTerminatorBeforeArrow : boolean } interface LiteralExpression extends PrimaryExpression { >LiteralExpression : LiteralExpression diff --git a/tests/baselines/reference/APISample_transform.js b/tests/baselines/reference/APISample_transform.js index bfe62135a0db3..2d39e9a3c0c38 100644 --- a/tests/baselines/reference/APISample_transform.js +++ b/tests/baselines/reference/APISample_transform.js @@ -585,6 +585,9 @@ declare module "typescript" { name?: Identifier; body: Block | Expression; } + interface ArrowFunctionExpression extends FunctionExpression { + lineTerminatorBeforeArrow: boolean; + } interface LiteralExpression extends PrimaryExpression { text: string; isUnterminated?: boolean; diff --git a/tests/baselines/reference/APISample_transform.types b/tests/baselines/reference/APISample_transform.types index baa497c95fa50..d9d1482fbc874 100644 --- a/tests/baselines/reference/APISample_transform.types +++ b/tests/baselines/reference/APISample_transform.types @@ -1764,6 +1764,13 @@ declare module "typescript" { >body : Expression | Block >Block : Block >Expression : Expression + } + interface ArrowFunctionExpression extends FunctionExpression { +>ArrowFunctionExpression : ArrowFunctionExpression +>FunctionExpression : FunctionExpression + + lineTerminatorBeforeArrow: boolean; +>lineTerminatorBeforeArrow : boolean } interface LiteralExpression extends PrimaryExpression { >LiteralExpression : LiteralExpression diff --git a/tests/baselines/reference/APISample_watcher.js b/tests/baselines/reference/APISample_watcher.js index ee1fd06251576..7fa2a92afae9e 100644 --- a/tests/baselines/reference/APISample_watcher.js +++ b/tests/baselines/reference/APISample_watcher.js @@ -622,6 +622,9 @@ declare module "typescript" { name?: Identifier; body: Block | Expression; } + interface ArrowFunctionExpression extends FunctionExpression { + lineTerminatorBeforeArrow: boolean; + } interface LiteralExpression extends PrimaryExpression { text: string; isUnterminated?: boolean; diff --git a/tests/baselines/reference/APISample_watcher.types b/tests/baselines/reference/APISample_watcher.types index a8b534439d546..23f7ffb714899 100644 --- a/tests/baselines/reference/APISample_watcher.types +++ b/tests/baselines/reference/APISample_watcher.types @@ -1937,6 +1937,13 @@ declare module "typescript" { >body : Expression | Block >Block : Block >Expression : Expression + } + interface ArrowFunctionExpression extends FunctionExpression { +>ArrowFunctionExpression : ArrowFunctionExpression +>FunctionExpression : FunctionExpression + + lineTerminatorBeforeArrow: boolean; +>lineTerminatorBeforeArrow : boolean } interface LiteralExpression extends PrimaryExpression { >LiteralExpression : LiteralExpression diff --git a/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt b/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt index 0450903f7174c..c64d42b7fffd2 100644 --- a/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt +++ b/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt @@ -1,70 +1,66 @@ -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(2,5): error TS1109: Expression expected. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(4,7): error TS1109: Expression expected. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(6,5): error TS1109: Expression expected. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(8,7): error TS1109: Expression expected. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(10,5): error TS1109: Expression expected. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(12,7): error TS1109: Expression expected. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(14,5): error TS1109: Expression expected. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(16,7): error TS1109: Expression expected. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(19,1): error TS2346: Supplied parameters do not match any signature of call target. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(20,5): error TS1109: Expression expected. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(21,1): error TS2346: Supplied parameters do not match any signature of call target. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(22,5): error TS1109: Expression expected. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(22,17): error TS1005: ':' expected. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(22,22): error TS1005: ',' expected. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(1,10): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(3,10): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(5,10): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(7,10): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(9,10): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(11,10): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(13,10): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(15,10): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(19,5): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(21,5): error TS1200: Line terminator not permitted before arrow. -==== tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts (14 errors) ==== +==== tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts (10 errors) ==== var f1 = () + ~~ => { } - ~~ -!!! error TS1109: Expression expected. + ~~~~~~~~~~ +!!! error TS1200: Line terminator not permitted before arrow. var f2 = (x: string, y: string) /* + ~~~~~~~~~~~~~~~~~~~~~~~~~ */ => { } - ~~ -!!! error TS1109: Expression expected. + ~~~~~~~~~~~~ +!!! error TS1200: Line terminator not permitted before arrow. var f3 = (x: string, y: number, ...rest) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ => { } - ~~ -!!! error TS1109: Expression expected. + ~~~~~~~~~~ +!!! error TS1200: Line terminator not permitted before arrow. var f4 = (x: string, y: number, ...rest) /* + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ => { } - ~~ -!!! error TS1109: Expression expected. + ~~~~~~~~~~~~ +!!! error TS1200: Line terminator not permitted before arrow. var f5 = (...rest) + ~~~~~~~~~ => { } - ~~ -!!! error TS1109: Expression expected. + ~~~~~~~~~~ +!!! error TS1200: Line terminator not permitted before arrow. var f6 = (...rest) /* + ~~~~~~~~~~~~ */ => { } - ~~ -!!! error TS1109: Expression expected. + ~~~~~~~~~~~~ +!!! error TS1200: Line terminator not permitted before arrow. var f7 = (x: string, y: number, z = 10) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ => { } - ~~ -!!! error TS1109: Expression expected. + ~~~~~~~~~~ +!!! error TS1200: Line terminator not permitted before arrow. var f8 = (x: string, y: number, z = 10) /* + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ => { } - ~~ -!!! error TS1109: Expression expected. + ~~~~~~~~~~~~ +!!! error TS1200: Line terminator not permitted before arrow. function foo(func: () => boolean) { } foo(() - ~~~~~~ - => true); - ~~~~~~~~~~~~ -!!! error TS2346: Supplied parameters do not match any signature of call target. ~~ -!!! error TS1109: Expression expected. + => true); + ~~~~~~~~~~~ +!!! error TS1200: Line terminator not permitted before arrow. foo(() - ~~~~~~ - => { return false; }); - ~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2346: Supplied parameters do not match any signature of call target. ~~ -!!! error TS1109: Expression expected. - ~~~~~ -!!! error TS1005: ':' expected. - ~ -!!! error TS1005: ',' expected. + => { return false; }); + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS1200: Line terminator not permitted before arrow. \ No newline at end of file diff --git a/tests/baselines/reference/disallowLineTerminatorBeforeArrow.js b/tests/baselines/reference/disallowLineTerminatorBeforeArrow.js index c98b6a89d4f16..2619b41bf3881 100644 --- a/tests/baselines/reference/disallowLineTerminatorBeforeArrow.js +++ b/tests/baselines/reference/disallowLineTerminatorBeforeArrow.js @@ -24,37 +24,45 @@ foo(() //// [disallowLineTerminatorBeforeArrow.js] -var f1 = ; -{ -} -var f2 = ; /* - */ -{ -} -var f3 = ; -{ -} -var f4 = ; /* - */ -{ -} -var f5 = ; -{ -} -var f6 = ; /* - */ -{ -} -var f7 = ; -{ -} -var f8 = ; /* - */ -{ -} +var f1 = function () { +}; +var f2 = function (x, y) { +}; +var f3 = function (x, y) { + var rest = []; + for (var _i = 2; _i < arguments.length; _i++) { + rest[_i - 2] = arguments[_i]; + } +}; +var f4 = function (x, y) { + var rest = []; + for (var _i = 2; _i < arguments.length; _i++) { + rest[_i - 2] = arguments[_i]; + } +}; +var f5 = function () { + var rest = []; + for (var _i = 0; _i < arguments.length; _i++) { + rest[_i - 0] = arguments[_i]; + } +}; +var f6 = function () { + var rest = []; + for (var _i = 0; _i < arguments.length; _i++) { + rest[_i - 0] = arguments[_i]; + } +}; +var f7 = function (x, y, z) { + if (z === void 0) { z = 10; } +}; +var f8 = function (x, y, z) { + if (z === void 0) { z = 10; } +}; function foo(func) { } -foo(, true); -foo(, { - return: false +foo(function () { + return true; +}); +foo(function () { + return false; }); From 231f522d8967dd103246ed4f7aeb2048b7ffff64 Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Tue, 10 Mar 2015 17:20:28 -0400 Subject: [PATCH 03/10] Add additional test-cases for arrow function grammar As suggested by @DanielRosenwasser --- ...sallowLineTerminatorBeforeArrow.errors.txt | 37 +++++++++++++++- .../disallowLineTerminatorBeforeArrow.js | 42 +++++++++++++++++++ .../disallowLineTerminatorBeforeArrow.ts | 19 +++++++++ 3 files changed, 97 insertions(+), 1 deletion(-) diff --git a/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt b/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt index c64d42b7fffd2..e9f079985048a 100644 --- a/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt +++ b/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt @@ -8,9 +8,13 @@ tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(1 tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(15,10): error TS1200: Line terminator not permitted before arrow. tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(19,5): error TS1200: Line terminator not permitted before arrow. tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(21,5): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(26,40): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(30,20): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(35,17): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(39,20): error TS1200: Line terminator not permitted before arrow. -==== tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts (10 errors) ==== +==== tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts (14 errors) ==== var f1 = () ~~ => { } @@ -63,4 +67,35 @@ tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(2 => { return false; }); ~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS1200: Line terminator not permitted before arrow. + + module m { + class City { + constructor(x: number, thing = () + ~~ + => 100) { + ~~~~~~~~~~~~~~~~~~ +!!! error TS1200: Line terminator not permitted before arrow. + } + + public m = () + ~~ + => 2 * 2 * 2 + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS1200: Line terminator not permitted before arrow. + } + + export enum Enum { + claw = (() + ~~ + => 10)() + ~~~~~~~~~~~~~~~~~ +!!! error TS1200: Line terminator not permitted before arrow. + } + + export var v = x + ~ + => new City(Enum.claw); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS1200: Line terminator not permitted before arrow. + } \ No newline at end of file diff --git a/tests/baselines/reference/disallowLineTerminatorBeforeArrow.js b/tests/baselines/reference/disallowLineTerminatorBeforeArrow.js index 2619b41bf3881..122c229d7d948 100644 --- a/tests/baselines/reference/disallowLineTerminatorBeforeArrow.js +++ b/tests/baselines/reference/disallowLineTerminatorBeforeArrow.js @@ -21,6 +21,25 @@ foo(() => true); foo(() => { return false; }); + +module m { + class City { + constructor(x: number, thing = () + => 100) { + } + + public m = () + => 2 * 2 * 2 + } + + export enum Enum { + claw = (() + => 10)() + } + + export var v = x + => new City(Enum.claw); +} //// [disallowLineTerminatorBeforeArrow.js] @@ -66,3 +85,26 @@ foo(function () { foo(function () { return false; }); +var m; +(function (m) { + var City = (function () { + function City(x, thing) { + if (thing === void 0) { thing = function () { + return 100; + }; } + this.m = function () { + return 2 * 2 * 2; + }; + } + return City; + })(); + (function (Enum) { + Enum[Enum["claw"] = (function () { + return 10; + })()] = "claw"; + })(m.Enum || (m.Enum = {})); + var Enum = m.Enum; + m.v = function (x) { + return new City(Enum.claw); + }; +})(m || (m = {})); diff --git a/tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts b/tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts index 316ff92c56c12..f11fed6b47813 100644 --- a/tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts +++ b/tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts @@ -20,3 +20,22 @@ foo(() => true); foo(() => { return false; }); + +module m { + class City { + constructor(x: number, thing = () + => 100) { + } + + public m = () + => 2 * 2 * 2 + } + + export enum Enum { + claw = (() + => 10)() + } + + export var v = x + => new City(Enum.claw); +} From aa3cefb63d75ec91b50717ffb41e994b6dd0b3f6 Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Tue, 10 Mar 2015 20:59:16 -0400 Subject: [PATCH 04/10] Check that arrow is on same line as parameters --- src/compiler/checker.ts | 11 +-- src/compiler/parser.ts | 19 ++--- src/compiler/types.ts | 4 +- .../baselines/reference/APISample_compile.js | 4 +- .../reference/APISample_compile.types | 12 ++-- tests/baselines/reference/APISample_linter.js | 4 +- .../reference/APISample_linter.types | 12 ++-- .../reference/APISample_transform.js | 4 +- .../reference/APISample_transform.types | 12 ++-- .../baselines/reference/APISample_watcher.js | 4 +- .../reference/APISample_watcher.types | 12 ++-- ...sallowLineTerminatorBeforeArrow.errors.txt | 70 ++++++++----------- 12 files changed, 82 insertions(+), 86 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dae254253ca95..8322bb7c5d3cd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11381,11 +11381,12 @@ module ts { } function checkGrammarArrowFunction(node: FunctionLikeDeclaration): boolean { - if (node.kind === SyntaxKind.ArrowFunction) { - if ((node).lineTerminatorBeforeArrow) { - grammarErrorOnNode(node, Diagnostics.Line_terminator_not_permitted_before_arrow); - return true; - } + if (node.kind === SyntaxKind.ArrowFunction && (node).arrow) { + var arrowFunction = node; + var sourceFile = getSourceFileOfNode(node); + if (getLineAndCharacterOfPosition(sourceFile, getTokenPosOfNode(arrowFunction.arrow, sourceFile)).line !== getLineAndCharacterOfPosition(sourceFile, arrowFunction.parameters.end).line) { + return grammarErrorOnNode(arrowFunction.arrow, Diagnostics.Line_terminator_not_permitted_before_arrow); + } } return false; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 06655b1d822f3..6b010f584a2a8 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -95,6 +95,7 @@ module ts { visitNodes(cbNodes, (node).typeParameters) || visitNodes(cbNodes, (node).parameters) || visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).arrow) || visitNode(cbNode, (node).body); case SyntaxKind.TypeReference: return visitNode(cbNode, (node).typeName) || @@ -3006,18 +3007,19 @@ module ts { function parseSimpleArrowFunctionExpression(identifier: Identifier): Expression { Debug.assert(token === SyntaxKind.EqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>"); - let node = createNode(SyntaxKind.ArrowFunction, identifier.pos); + let node = createNode(SyntaxKind.ArrowFunction, identifier.pos); let parameter = createNode(SyntaxKind.Parameter, identifier.pos); - parameter.name = identifier; + parameter.name = identifier; finishNode(parameter); node.parameters = >[parameter]; node.parameters.pos = parameter.pos; node.parameters.end = parameter.end; - node.lineTerminatorBeforeArrow = scanner.hasPrecedingLineBreak(); - parseExpected(SyntaxKind.EqualsGreaterThanToken); + if ((node.arrow = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, false, Diagnostics._0_expected, "=>"))) { + node.arrow.parent = node; + } node.body = parseArrowFunctionExpressionBody(); return finishNode(node); @@ -3046,7 +3048,8 @@ module ts { // If we have an arrow, then try to parse the body. Even if not, try to parse if we // have an opening brace, just in case we're in an error state. - if (parseExpected(SyntaxKind.EqualsGreaterThanToken) || token === SyntaxKind.OpenBraceToken) { + if ((arrowFunction.arrow = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, false, Diagnostics._0_expected, "=>")) || token === SyntaxKind.OpenBraceToken) { + arrowFunction.arrow.parent = arrowFunction; arrowFunction.body = parseArrowFunctionExpressionBody(); } else { @@ -3141,9 +3144,9 @@ module ts { } function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): FunctionExpression { - let node = createNode(SyntaxKind.ArrowFunction); + let node = createNode(SyntaxKind.ArrowFunction); // Arrow functions are never generators. - // + // // If we're speculatively parsing a signature for a parenthesized arrow function, then // we have to have a complete parameter list. Otherwise we might see something like // a => (b => c) @@ -3169,8 +3172,6 @@ module ts { return undefined; } - node.lineTerminatorBeforeArrow = scanner.hasPrecedingLineBreak(); - return node; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 56820a10924f5..49529bed9c6c5 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -653,8 +653,8 @@ module ts { body: Block | Expression; // Required, whereas the member inherited from FunctionDeclaration is optional } - export interface ArrowFunctionExpression extends FunctionExpression { - lineTerminatorBeforeArrow: boolean; + export interface ArrowFunction extends Expression, FunctionLikeDeclaration { + arrow: Node; } // The text property of a LiteralExpression stores the interpreted value of the literal in text form. For a StringLiteral, diff --git a/tests/baselines/reference/APISample_compile.js b/tests/baselines/reference/APISample_compile.js index 316649a35c978..997bd2bd33740 100644 --- a/tests/baselines/reference/APISample_compile.js +++ b/tests/baselines/reference/APISample_compile.js @@ -553,8 +553,8 @@ declare module "typescript" { name?: Identifier; body: Block | Expression; } - interface ArrowFunctionExpression extends FunctionExpression { - lineTerminatorBeforeArrow: boolean; + interface ArrowFunction extends Expression, FunctionLikeDeclaration { + arrow: Node; } interface LiteralExpression extends PrimaryExpression { text: string; diff --git a/tests/baselines/reference/APISample_compile.types b/tests/baselines/reference/APISample_compile.types index bf51bb946c015..d91d860ca8f72 100644 --- a/tests/baselines/reference/APISample_compile.types +++ b/tests/baselines/reference/APISample_compile.types @@ -1669,12 +1669,14 @@ declare module "typescript" { >Block : Block >Expression : Expression } - interface ArrowFunctionExpression extends FunctionExpression { ->ArrowFunctionExpression : ArrowFunctionExpression ->FunctionExpression : FunctionExpression + interface ArrowFunction extends Expression, FunctionLikeDeclaration { +>ArrowFunction : ArrowFunction +>Expression : Expression +>FunctionLikeDeclaration : FunctionLikeDeclaration - lineTerminatorBeforeArrow: boolean; ->lineTerminatorBeforeArrow : boolean + arrow: Node; +>arrow : Node +>Node : Node } interface LiteralExpression extends PrimaryExpression { >LiteralExpression : LiteralExpression diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index 5f7dc308820c8..b941acdbc52ae 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -584,8 +584,8 @@ declare module "typescript" { name?: Identifier; body: Block | Expression; } - interface ArrowFunctionExpression extends FunctionExpression { - lineTerminatorBeforeArrow: boolean; + interface ArrowFunction extends Expression, FunctionLikeDeclaration { + arrow: Node; } interface LiteralExpression extends PrimaryExpression { text: string; diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index ede73749eb018..b8701020e0354 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -1815,12 +1815,14 @@ declare module "typescript" { >Block : Block >Expression : Expression } - interface ArrowFunctionExpression extends FunctionExpression { ->ArrowFunctionExpression : ArrowFunctionExpression ->FunctionExpression : FunctionExpression + interface ArrowFunction extends Expression, FunctionLikeDeclaration { +>ArrowFunction : ArrowFunction +>Expression : Expression +>FunctionLikeDeclaration : FunctionLikeDeclaration - lineTerminatorBeforeArrow: boolean; ->lineTerminatorBeforeArrow : boolean + arrow: Node; +>arrow : Node +>Node : Node } interface LiteralExpression extends PrimaryExpression { >LiteralExpression : LiteralExpression diff --git a/tests/baselines/reference/APISample_transform.js b/tests/baselines/reference/APISample_transform.js index 2d39e9a3c0c38..baf3f9d850318 100644 --- a/tests/baselines/reference/APISample_transform.js +++ b/tests/baselines/reference/APISample_transform.js @@ -585,8 +585,8 @@ declare module "typescript" { name?: Identifier; body: Block | Expression; } - interface ArrowFunctionExpression extends FunctionExpression { - lineTerminatorBeforeArrow: boolean; + interface ArrowFunction extends Expression, FunctionLikeDeclaration { + arrow: Node; } interface LiteralExpression extends PrimaryExpression { text: string; diff --git a/tests/baselines/reference/APISample_transform.types b/tests/baselines/reference/APISample_transform.types index d9d1482fbc874..d214a6fc959a7 100644 --- a/tests/baselines/reference/APISample_transform.types +++ b/tests/baselines/reference/APISample_transform.types @@ -1765,12 +1765,14 @@ declare module "typescript" { >Block : Block >Expression : Expression } - interface ArrowFunctionExpression extends FunctionExpression { ->ArrowFunctionExpression : ArrowFunctionExpression ->FunctionExpression : FunctionExpression + interface ArrowFunction extends Expression, FunctionLikeDeclaration { +>ArrowFunction : ArrowFunction +>Expression : Expression +>FunctionLikeDeclaration : FunctionLikeDeclaration - lineTerminatorBeforeArrow: boolean; ->lineTerminatorBeforeArrow : boolean + arrow: Node; +>arrow : Node +>Node : Node } interface LiteralExpression extends PrimaryExpression { >LiteralExpression : LiteralExpression diff --git a/tests/baselines/reference/APISample_watcher.js b/tests/baselines/reference/APISample_watcher.js index 7fa2a92afae9e..d963aaff481a4 100644 --- a/tests/baselines/reference/APISample_watcher.js +++ b/tests/baselines/reference/APISample_watcher.js @@ -622,8 +622,8 @@ declare module "typescript" { name?: Identifier; body: Block | Expression; } - interface ArrowFunctionExpression extends FunctionExpression { - lineTerminatorBeforeArrow: boolean; + interface ArrowFunction extends Expression, FunctionLikeDeclaration { + arrow: Node; } interface LiteralExpression extends PrimaryExpression { text: string; diff --git a/tests/baselines/reference/APISample_watcher.types b/tests/baselines/reference/APISample_watcher.types index 23f7ffb714899..da00b9bf46631 100644 --- a/tests/baselines/reference/APISample_watcher.types +++ b/tests/baselines/reference/APISample_watcher.types @@ -1938,12 +1938,14 @@ declare module "typescript" { >Block : Block >Expression : Expression } - interface ArrowFunctionExpression extends FunctionExpression { ->ArrowFunctionExpression : ArrowFunctionExpression ->FunctionExpression : FunctionExpression + interface ArrowFunction extends Expression, FunctionLikeDeclaration { +>ArrowFunction : ArrowFunction +>Expression : Expression +>FunctionLikeDeclaration : FunctionLikeDeclaration - lineTerminatorBeforeArrow: boolean; ->lineTerminatorBeforeArrow : boolean + arrow: Node; +>arrow : Node +>Node : Node } interface LiteralExpression extends PrimaryExpression { >LiteralExpression : LiteralExpression diff --git a/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt b/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt index e9f079985048a..e441752338c12 100644 --- a/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt +++ b/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt @@ -1,101 +1,87 @@ -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(1,10): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(3,10): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(5,10): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(7,10): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(9,10): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(11,10): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(13,10): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(15,10): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(19,5): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(21,5): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(26,40): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(30,20): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(35,17): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(39,20): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(2,5): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(4,7): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(6,5): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(8,7): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(10,5): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(12,7): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(14,5): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(16,7): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(20,5): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(22,5): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(27,13): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(31,13): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(36,13): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(40,9): error TS1200: Line terminator not permitted before arrow. ==== tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts (14 errors) ==== var f1 = () - ~~ => { } - ~~~~~~~~~~ + ~~ !!! error TS1200: Line terminator not permitted before arrow. var f2 = (x: string, y: string) /* - ~~~~~~~~~~~~~~~~~~~~~~~~~ */ => { } - ~~~~~~~~~~~~ + ~~ !!! error TS1200: Line terminator not permitted before arrow. var f3 = (x: string, y: number, ...rest) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ => { } - ~~~~~~~~~~ + ~~ !!! error TS1200: Line terminator not permitted before arrow. var f4 = (x: string, y: number, ...rest) /* - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ => { } - ~~~~~~~~~~~~ + ~~ !!! error TS1200: Line terminator not permitted before arrow. var f5 = (...rest) - ~~~~~~~~~ => { } - ~~~~~~~~~~ + ~~ !!! error TS1200: Line terminator not permitted before arrow. var f6 = (...rest) /* - ~~~~~~~~~~~~ */ => { } - ~~~~~~~~~~~~ + ~~ !!! error TS1200: Line terminator not permitted before arrow. var f7 = (x: string, y: number, z = 10) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ => { } - ~~~~~~~~~~ + ~~ !!! error TS1200: Line terminator not permitted before arrow. var f8 = (x: string, y: number, z = 10) /* - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ => { } - ~~~~~~~~~~~~ + ~~ !!! error TS1200: Line terminator not permitted before arrow. function foo(func: () => boolean) { } foo(() - ~~ => true); - ~~~~~~~~~~~ + ~~ !!! error TS1200: Line terminator not permitted before arrow. foo(() - ~~ => { return false; }); - ~~~~~~~~~~~~~~~~~~~~~~~~ + ~~ !!! error TS1200: Line terminator not permitted before arrow. module m { class City { constructor(x: number, thing = () - ~~ => 100) { - ~~~~~~~~~~~~~~~~~~ + ~~ !!! error TS1200: Line terminator not permitted before arrow. } public m = () - ~~ => 2 * 2 * 2 - ~~~~~~~~~~~~~~~~~~~~~~~~ + ~~ !!! error TS1200: Line terminator not permitted before arrow. } export enum Enum { claw = (() - ~~ => 10)() - ~~~~~~~~~~~~~~~~~ + ~~ !!! error TS1200: Line terminator not permitted before arrow. } export var v = x - ~ => new City(Enum.claw); - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~ !!! error TS1200: Line terminator not permitted before arrow. } \ No newline at end of file From fdc673f5eba6d0709a340cd67790e0a670175d89 Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Tue, 10 Mar 2015 21:07:05 -0400 Subject: [PATCH 05/10] Fix line wrapping --- src/compiler/checker.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8322bb7c5d3cd..d0c9ff8714009 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11384,7 +11384,8 @@ module ts { if (node.kind === SyntaxKind.ArrowFunction && (node).arrow) { var arrowFunction = node; var sourceFile = getSourceFileOfNode(node); - if (getLineAndCharacterOfPosition(sourceFile, getTokenPosOfNode(arrowFunction.arrow, sourceFile)).line !== getLineAndCharacterOfPosition(sourceFile, arrowFunction.parameters.end).line) { + if (getLineAndCharacterOfPosition(sourceFile, getTokenPosOfNode(arrowFunction.arrow, sourceFile)).line !== + getLineAndCharacterOfPosition(sourceFile, arrowFunction.parameters.end).line) { return grammarErrorOnNode(arrowFunction.arrow, Diagnostics.Line_terminator_not_permitted_before_arrow); } } From 5e107e6042cc83bf7071051631fe4b6c0bd61ae0 Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Tue, 10 Mar 2015 21:22:41 -0400 Subject: [PATCH 06/10] Address slew of review comments --- src/compiler/checker.ts | 9 +++++---- src/compiler/parser.ts | 9 +++------ src/compiler/types.ts | 2 +- tests/baselines/reference/APISample_compile.js | 2 +- tests/baselines/reference/APISample_compile.types | 4 ++-- tests/baselines/reference/APISample_linter.js | 2 +- tests/baselines/reference/APISample_linter.types | 4 ++-- tests/baselines/reference/APISample_transform.js | 2 +- tests/baselines/reference/APISample_transform.types | 4 ++-- tests/baselines/reference/APISample_watcher.js | 2 +- tests/baselines/reference/APISample_watcher.types | 4 ++-- 11 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d0c9ff8714009..df1b70ab6ff48 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11381,12 +11381,13 @@ module ts { } function checkGrammarArrowFunction(node: FunctionLikeDeclaration): boolean { - if (node.kind === SyntaxKind.ArrowFunction && (node).arrow) { + if (node.kind === SyntaxKind.ArrowFunction) { var arrowFunction = node; var sourceFile = getSourceFileOfNode(node); - if (getLineAndCharacterOfPosition(sourceFile, getTokenPosOfNode(arrowFunction.arrow, sourceFile)).line !== - getLineAndCharacterOfPosition(sourceFile, arrowFunction.parameters.end).line) { - return grammarErrorOnNode(arrowFunction.arrow, Diagnostics.Line_terminator_not_permitted_before_arrow); + var equalsGreaterThanLine = getLineAndCharacterOfPosition(sourceFile, getTokenPosOfNode(arrowFunction.equalsGreaterThanToken, sourceFile)).line; + var parametersLine = getLineAndCharacterOfPosition(sourceFile, arrowFunction.parameters.end).line; + if (equalsGreaterThanLine !== parametersLine) { + return grammarErrorOnNode(arrowFunction.equalsGreaterThanToken, Diagnostics.Line_terminator_not_permitted_before_arrow); } } return false; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 6b010f584a2a8..5756f379685a1 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -95,7 +95,7 @@ module ts { visitNodes(cbNodes, (node).typeParameters) || visitNodes(cbNodes, (node).parameters) || visitNode(cbNode, (node).type) || - visitNode(cbNode, (node).arrow) || + visitNode(cbNode, (node).equalsGreaterThanToken) || visitNode(cbNode, (node).body); case SyntaxKind.TypeReference: return visitNode(cbNode, (node).typeName) || @@ -3017,9 +3017,7 @@ module ts { node.parameters.pos = parameter.pos; node.parameters.end = parameter.end; - if ((node.arrow = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, false, Diagnostics._0_expected, "=>"))) { - node.arrow.parent = node; - } + node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, false, Diagnostics._0_expected, "=>"); node.body = parseArrowFunctionExpressionBody(); return finishNode(node); @@ -3048,8 +3046,7 @@ module ts { // If we have an arrow, then try to parse the body. Even if not, try to parse if we // have an opening brace, just in case we're in an error state. - if ((arrowFunction.arrow = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, false, Diagnostics._0_expected, "=>")) || token === SyntaxKind.OpenBraceToken) { - arrowFunction.arrow.parent = arrowFunction; + if ((arrowFunction.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, false, Diagnostics._0_expected, "=>")) || token === SyntaxKind.OpenBraceToken) { arrowFunction.body = parseArrowFunctionExpressionBody(); } else { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 49529bed9c6c5..25a8ce75245ab 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -654,7 +654,7 @@ module ts { } export interface ArrowFunction extends Expression, FunctionLikeDeclaration { - arrow: Node; + equalsGreaterThanToken: Node; } // The text property of a LiteralExpression stores the interpreted value of the literal in text form. For a StringLiteral, diff --git a/tests/baselines/reference/APISample_compile.js b/tests/baselines/reference/APISample_compile.js index 997bd2bd33740..6244dc73951f6 100644 --- a/tests/baselines/reference/APISample_compile.js +++ b/tests/baselines/reference/APISample_compile.js @@ -554,7 +554,7 @@ declare module "typescript" { body: Block | Expression; } interface ArrowFunction extends Expression, FunctionLikeDeclaration { - arrow: Node; + equalsGreaterThanToken: Node; } interface LiteralExpression extends PrimaryExpression { text: string; diff --git a/tests/baselines/reference/APISample_compile.types b/tests/baselines/reference/APISample_compile.types index d91d860ca8f72..43e88c27e414b 100644 --- a/tests/baselines/reference/APISample_compile.types +++ b/tests/baselines/reference/APISample_compile.types @@ -1674,8 +1674,8 @@ declare module "typescript" { >Expression : Expression >FunctionLikeDeclaration : FunctionLikeDeclaration - arrow: Node; ->arrow : Node + equalsGreaterThanToken: Node; +>equalsGreaterThanToken : Node >Node : Node } interface LiteralExpression extends PrimaryExpression { diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index b941acdbc52ae..fd4649f614daf 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -585,7 +585,7 @@ declare module "typescript" { body: Block | Expression; } interface ArrowFunction extends Expression, FunctionLikeDeclaration { - arrow: Node; + equalsGreaterThanToken: Node; } interface LiteralExpression extends PrimaryExpression { text: string; diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index b8701020e0354..984b59ca7ee74 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -1820,8 +1820,8 @@ declare module "typescript" { >Expression : Expression >FunctionLikeDeclaration : FunctionLikeDeclaration - arrow: Node; ->arrow : Node + equalsGreaterThanToken: Node; +>equalsGreaterThanToken : Node >Node : Node } interface LiteralExpression extends PrimaryExpression { diff --git a/tests/baselines/reference/APISample_transform.js b/tests/baselines/reference/APISample_transform.js index baf3f9d850318..4222e1b2d98fb 100644 --- a/tests/baselines/reference/APISample_transform.js +++ b/tests/baselines/reference/APISample_transform.js @@ -586,7 +586,7 @@ declare module "typescript" { body: Block | Expression; } interface ArrowFunction extends Expression, FunctionLikeDeclaration { - arrow: Node; + equalsGreaterThanToken: Node; } interface LiteralExpression extends PrimaryExpression { text: string; diff --git a/tests/baselines/reference/APISample_transform.types b/tests/baselines/reference/APISample_transform.types index d214a6fc959a7..bea3f1e723146 100644 --- a/tests/baselines/reference/APISample_transform.types +++ b/tests/baselines/reference/APISample_transform.types @@ -1770,8 +1770,8 @@ declare module "typescript" { >Expression : Expression >FunctionLikeDeclaration : FunctionLikeDeclaration - arrow: Node; ->arrow : Node + equalsGreaterThanToken: Node; +>equalsGreaterThanToken : Node >Node : Node } interface LiteralExpression extends PrimaryExpression { diff --git a/tests/baselines/reference/APISample_watcher.js b/tests/baselines/reference/APISample_watcher.js index d963aaff481a4..0928c2cf13988 100644 --- a/tests/baselines/reference/APISample_watcher.js +++ b/tests/baselines/reference/APISample_watcher.js @@ -623,7 +623,7 @@ declare module "typescript" { body: Block | Expression; } interface ArrowFunction extends Expression, FunctionLikeDeclaration { - arrow: Node; + equalsGreaterThanToken: Node; } interface LiteralExpression extends PrimaryExpression { text: string; diff --git a/tests/baselines/reference/APISample_watcher.types b/tests/baselines/reference/APISample_watcher.types index da00b9bf46631..4498a5538e4e9 100644 --- a/tests/baselines/reference/APISample_watcher.types +++ b/tests/baselines/reference/APISample_watcher.types @@ -1943,8 +1943,8 @@ declare module "typescript" { >Expression : Expression >FunctionLikeDeclaration : FunctionLikeDeclaration - arrow: Node; ->arrow : Node + equalsGreaterThanToken: Node; +>equalsGreaterThanToken : Node >Node : Node } interface LiteralExpression extends PrimaryExpression { From bd828e3024ecd34f60df57ee20514d637b198945 Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Tue, 10 Mar 2015 22:14:58 -0400 Subject: [PATCH 07/10] Parse arrow function body as identifier if missing => or { Restores functionality broken in previous commit --- src/compiler/parser.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 5756f379685a1..eb43f7746053f 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3046,7 +3046,8 @@ module ts { // If we have an arrow, then try to parse the body. Even if not, try to parse if we // have an opening brace, just in case we're in an error state. - if ((arrowFunction.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, false, Diagnostics._0_expected, "=>")) || token === SyntaxKind.OpenBraceToken) { + arrowFunction.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, false, Diagnostics._0_expected, "=>"); + if (arrowFunction.equalsGreaterThanToken.kind === SyntaxKind.EqualsGreaterThanToken || token === SyntaxKind.OpenBraceToken) { arrowFunction.body = parseArrowFunctionExpressionBody(); } else { From 3dc5faf70779d286405faf05b240feac7687f001 Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Wed, 11 Mar 2015 16:40:31 -0400 Subject: [PATCH 08/10] Restore earlier behaviour when parsing non-simple arrow function bodies --- src/compiler/parser.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index eb43f7746053f..f996af5f5e44c 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3046,14 +3046,11 @@ module ts { // If we have an arrow, then try to parse the body. Even if not, try to parse if we // have an opening brace, just in case we're in an error state. - arrowFunction.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, false, Diagnostics._0_expected, "=>"); - if (arrowFunction.equalsGreaterThanToken.kind === SyntaxKind.EqualsGreaterThanToken || token === SyntaxKind.OpenBraceToken) { - arrowFunction.body = parseArrowFunctionExpressionBody(); - } - else { - // If not, we're probably better off bailing out and returning a bogus function expression. - arrowFunction.body = parseIdentifier(); - } + var lastToken = token; + arrowFunction.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, /*reportAtCurrentPosition:*/false, Diagnostics._0_expected, "=>"); + arrowFunction.body = (lastToken === SyntaxKind.EqualsGreaterThanToken || lastToken === SyntaxKind.OpenBraceToken) + ? parseArrowFunctionExpressionBody() + : parseIdentifier(); return finishNode(arrowFunction); } From 10925c1e9ba8cd7d5babc76823c458fb0dbfc886 Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Fri, 13 Mar 2015 01:30:07 -0400 Subject: [PATCH 09/10] Make sure arrow function grammar rules can deal with type annotations --- src/compiler/checker.ts | 8 +-- ...sallowLineTerminatorBeforeArrow.errors.txt | 58 ++++++++++++++-- .../disallowLineTerminatorBeforeArrow.js | 68 +++++++++++++++++++ .../disallowLineTerminatorBeforeArrow.ts | 32 +++++++++ 4 files changed, 155 insertions(+), 11 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index df1b70ab6ff48..be1b6f943cac3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4412,7 +4412,7 @@ module ts { } /** - * Check if a Type was written as a tuple type literal. + * Check if a Type was written as a tuple type literal. * Prefer using isTupleLikeType() unless the use of `elementTypes` is required. */ function isTupleType(type: Type) : boolean { @@ -11384,9 +11384,9 @@ module ts { if (node.kind === SyntaxKind.ArrowFunction) { var arrowFunction = node; var sourceFile = getSourceFileOfNode(node); - var equalsGreaterThanLine = getLineAndCharacterOfPosition(sourceFile, getTokenPosOfNode(arrowFunction.equalsGreaterThanToken, sourceFile)).line; - var parametersLine = getLineAndCharacterOfPosition(sourceFile, arrowFunction.parameters.end).line; - if (equalsGreaterThanLine !== parametersLine) { + var startLine = getLineAndCharacterOfPosition(sourceFile, arrowFunction.equalsGreaterThanToken.pos).line; + var endLine = getLineAndCharacterOfPosition(sourceFile, arrowFunction.equalsGreaterThanToken.end).line; + if (startLine !== endLine) { return grammarErrorOnNode(arrowFunction.equalsGreaterThanToken, Diagnostics.Line_terminator_not_permitted_before_arrow); } } diff --git a/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt b/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt index e441752338c12..fbd9be772faab 100644 --- a/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt +++ b/tests/baselines/reference/disallowLineTerminatorBeforeArrow.errors.txt @@ -6,15 +6,19 @@ tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(1 tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(12,7): error TS1200: Line terminator not permitted before arrow. tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(14,5): error TS1200: Line terminator not permitted before arrow. tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(16,7): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(20,5): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(22,5): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(27,13): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(31,13): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(36,13): error TS1200: Line terminator not permitted before arrow. -tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(40,9): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(18,5): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(21,5): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(23,8): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(26,8): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(52,5): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(54,5): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(59,13): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(63,13): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(68,13): error TS1200: Line terminator not permitted before arrow. +tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(72,9): error TS1200: Line terminator not permitted before arrow. -==== tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts (14 errors) ==== +==== tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts (18 errors) ==== var f1 = () => { } ~~ @@ -47,6 +51,46 @@ tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts(4 */ => { } ~~ !!! error TS1200: Line terminator not permitted before arrow. + var f9 = (a: number): number + => a; + ~~ +!!! error TS1200: Line terminator not permitted before arrow. + var f10 = (a: number) : + number + => a + ~~ +!!! error TS1200: Line terminator not permitted before arrow. + var f11 = (a: number): number /* + */ => a; + ~~ +!!! error TS1200: Line terminator not permitted before arrow. + var f12 = (a: number) : + number /* + */ => a + ~~ +!!! error TS1200: Line terminator not permitted before arrow. + + // Should be valid. + var f11 = (a: number + ) => a; + + // Should be valid. + var f12 = (a: number) + : number => a; + + // Should be valid. + var f13 = (a: number): + number => a; + + // Should be valid. + var f14 = () /* */ => {} + + // Should be valid. + var f15 = (a: number): number /* */ => a + + // Should be valid. + var f16 = (a: number, b = 10): + number /* */ => a + b; function foo(func: () => boolean) { } foo(() diff --git a/tests/baselines/reference/disallowLineTerminatorBeforeArrow.js b/tests/baselines/reference/disallowLineTerminatorBeforeArrow.js index 122c229d7d948..610cbe62c1bd8 100644 --- a/tests/baselines/reference/disallowLineTerminatorBeforeArrow.js +++ b/tests/baselines/reference/disallowLineTerminatorBeforeArrow.js @@ -15,6 +15,38 @@ var f7 = (x: string, y: number, z = 10) => { } var f8 = (x: string, y: number, z = 10) /* */ => { } +var f9 = (a: number): number + => a; +var f10 = (a: number) : + number + => a +var f11 = (a: number): number /* + */ => a; +var f12 = (a: number) : + number /* + */ => a + +// Should be valid. +var f11 = (a: number + ) => a; + +// Should be valid. +var f12 = (a: number) + : number => a; + +// Should be valid. +var f13 = (a: number): + number => a; + +// Should be valid. +var f14 = () /* */ => {} + +// Should be valid. +var f15 = (a: number): number /* */ => a + +// Should be valid. +var f16 = (a: number, b = 10): + number /* */ => a + b; function foo(func: () => boolean) { } foo(() @@ -77,6 +109,42 @@ var f7 = function (x, y, z) { var f8 = function (x, y, z) { if (z === void 0) { z = 10; } }; +var f9 = function (a) { + return a; +}; +var f10 = function (a) { + return a; +}; +var f11 = function (a) { + return a; +}; +var f12 = function (a) { + return a; +}; +// Should be valid. +var f11 = function (a) { + return a; +}; +// Should be valid. +var f12 = function (a) { + return a; +}; +// Should be valid. +var f13 = function (a) { + return a; +}; +// Should be valid. +var f14 = function () { +}; +// Should be valid. +var f15 = function (a) { + return a; +}; +// Should be valid. +var f16 = function (a, b) { + if (b === void 0) { b = 10; } + return a + b; +}; function foo(func) { } foo(function () { diff --git a/tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts b/tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts index f11fed6b47813..bd984ba4da0e1 100644 --- a/tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts +++ b/tests/cases/conformance/es6/arrowFunction/disallowLineTerminatorBeforeArrow.ts @@ -14,6 +14,38 @@ var f7 = (x: string, y: number, z = 10) => { } var f8 = (x: string, y: number, z = 10) /* */ => { } +var f9 = (a: number): number + => a; +var f10 = (a: number) : + number + => a +var f11 = (a: number): number /* + */ => a; +var f12 = (a: number) : + number /* + */ => a + +// Should be valid. +var f11 = (a: number + ) => a; + +// Should be valid. +var f12 = (a: number) + : number => a; + +// Should be valid. +var f13 = (a: number): + number => a; + +// Should be valid. +var f14 = () /* */ => {} + +// Should be valid. +var f15 = (a: number): number /* */ => a + +// Should be valid. +var f16 = (a: number, b = 10): + number /* */ => a + b; function foo(func: () => boolean) { } foo(() From 02d356800f36ecd548641d993ab4b70359de2e70 Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Sat, 14 Mar 2015 20:12:10 -0400 Subject: [PATCH 10/10] Share SourceFile with other grammar checker that needs it --- src/compiler/checker.ts | 26 +++++++++++++------------- src/compiler/parser.ts | 4 ++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index be1b6f943cac3..03a4ee6d04ab5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -448,7 +448,7 @@ module ts { let declaration = forEach(result.declarations, d => isBlockOrCatchScoped(d) ? d : undefined); Debug.assert(declaration !== undefined, "Block-scoped variable declaration is undefined"); - + // first check if usage is lexically located after the declaration let isUsedBeforeDeclaration = !isDefinedBefore(declaration, errorLocation); if (!isUsedBeforeDeclaration) { @@ -465,7 +465,7 @@ module ts { if (variableDeclaration.parent.parent.kind === SyntaxKind.VariableStatement || variableDeclaration.parent.parent.kind === SyntaxKind.ForStatement) { - // variable statement/for statement case, + // variable statement/for statement case, // use site should not be inside variable declaration (initializer of declaration or binding element) isUsedBeforeDeclaration = isSameScopeDescendentOf(errorLocation, variableDeclaration, container); } @@ -9080,7 +9080,7 @@ module ts { */ function checkElementTypeOfArrayOrString(arrayOrStringType: Type, expressionForError: Expression): Type { Debug.assert(languageVersion < ScriptTarget.ES6); - + // After we remove all types that are StringLike, we will know if there was a string constituent // based on whether the remaining type is the same as the initial type. let arrayType = removeTypesFromUnionType(arrayOrStringType, TypeFlags.StringLike, /*isTypeOfKind*/ true, /*allowEmptyUnionResult*/ true); @@ -11324,16 +11324,15 @@ module ts { } } - function checkGrammarTypeParameterList(node: FunctionLikeDeclaration, typeParameters: NodeArray): boolean { + function checkGrammarTypeParameterList(node: FunctionLikeDeclaration, typeParameters: NodeArray, file: SourceFile): boolean { if (checkGrammarForDisallowedTrailingComma(typeParameters)) { return true; } if (typeParameters && typeParameters.length === 0) { let start = typeParameters.pos - "<".length; - let sourceFile = getSourceFileOfNode(node); - let end = skipTrivia(sourceFile.text, typeParameters.end) + ">".length; - return grammarErrorAtPos(sourceFile, start, end - start, Diagnostics.Type_parameter_list_cannot_be_empty); + let end = skipTrivia(file.text, typeParameters.end) + ">".length; + return grammarErrorAtPos(file, start, end - start, Diagnostics.Type_parameter_list_cannot_be_empty); } } @@ -11377,15 +11376,16 @@ module ts { function checkGrammarFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean { // Prevent cascading error by short-circuit - return checkGrammarModifiers(node) || checkGrammarTypeParameterList(node, node.typeParameters) || checkGrammarParameterList(node.parameters) || checkGrammarArrowFunction(node); + let file = getSourceFileOfNode(node); + return checkGrammarModifiers(node) || checkGrammarTypeParameterList(node, node.typeParameters, file) || + checkGrammarParameterList(node.parameters) || checkGrammarArrowFunction(node, file); } - function checkGrammarArrowFunction(node: FunctionLikeDeclaration): boolean { + function checkGrammarArrowFunction(node: FunctionLikeDeclaration, file: SourceFile): boolean { if (node.kind === SyntaxKind.ArrowFunction) { - var arrowFunction = node; - var sourceFile = getSourceFileOfNode(node); - var startLine = getLineAndCharacterOfPosition(sourceFile, arrowFunction.equalsGreaterThanToken.pos).line; - var endLine = getLineAndCharacterOfPosition(sourceFile, arrowFunction.equalsGreaterThanToken.end).line; + let arrowFunction = node; + let startLine = getLineAndCharacterOfPosition(file, arrowFunction.equalsGreaterThanToken.pos).line; + let endLine = getLineAndCharacterOfPosition(file, arrowFunction.equalsGreaterThanToken.end).line; if (startLine !== endLine) { return grammarErrorOnNode(arrowFunction.equalsGreaterThanToken, Diagnostics.Line_terminator_not_permitted_before_arrow); } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index f996af5f5e44c..27f550778c19d 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3134,11 +3134,11 @@ module ts { } } - function parsePossibleParenthesizedArrowFunctionExpressionHead() { + function parsePossibleParenthesizedArrowFunctionExpressionHead(): ArrowFunction { return parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity:*/ false); } - function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): FunctionExpression { + function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): ArrowFunction { let node = createNode(SyntaxKind.ArrowFunction); // Arrow functions are never generators. //