Browse Source

Give nice error message if returns is misspelt return

I often make this mistake so I assume others too.

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 5 years ago
parent
commit
4a906712c4
5 changed files with 326 additions and 284 deletions
  1. 1 0
      src/parser/pt.rs
  2. 15 6
      src/parser/solidity.lalrpop
  3. 285 278
      src/parser/solidity.rs
  4. 8 0
      src/sema/functions.rs
  5. 17 0
      tests/substrate_tests/functions.rs

+ 1 - 0
src/parser/pt.rs

@@ -478,6 +478,7 @@ pub struct FunctionDefinition {
     pub name_loc: Loc,
     pub params: Vec<(Loc, Option<Parameter>)>,
     pub attributes: Vec<FunctionAttribute>,
+    pub return_not_returns: Option<Loc>,
     pub returns: Vec<(Loc, Option<Parameter>)>,
     pub body: Option<Statement>,
 }

+ 15 - 6
src/parser/solidity.lalrpop

@@ -476,14 +476,19 @@ BlockStatementOrSemiColon: Option<Statement> = {
     BlockStatement => Some(<>),
 }
 
+returns: Option<Loc> = {
+    "returns" => None,
+    <l:@L> "return" <r:@R> => Some(Loc(file_no, l, r)),
+}
+
 // Modifiers can't have attributes or return values, but we parse them anyway so we can give nice
 // error messages. The parameter list is optional
 ModifierDefinition: Box<FunctionDefinition> = {
     <doc:DocComments> <l:@L> "modifier" <nl:@L> <name:Identifier> <nr:@R> <params:ParameterList?>
     <attributes:FunctionAttribute*>
-    <returns:("returns" <ParameterList>)?> <body:BlockStatementOrSemiColon> <r:@R> => {
+    <returns:(returns ParameterList)?> <body:BlockStatementOrSemiColon> <r:@R> => {
         let params = params.unwrap_or(Vec::new());
-        let returns = returns.unwrap_or(Vec::new());
+        let (return_not_returns, returns) = returns.unwrap_or((None, Vec::new()));
 
         Box::new(FunctionDefinition{
             doc,
@@ -493,6 +498,7 @@ ModifierDefinition: Box<FunctionDefinition> = {
             name_loc: Loc(file_no, nl, nr),
             params,
             attributes,
+            return_not_returns,
             returns,
             body,
         })
@@ -502,8 +508,8 @@ ModifierDefinition: Box<FunctionDefinition> = {
 ConstructorDefinition: Box<FunctionDefinition> = {
     <doc:DocComments> <l:@L> <ty:FunctionTy> <nl:@L> <name:Identifier?> <nr:@R> <params:ParameterList>
     <attributes:FunctionAttribute*>
-    <returns:("returns" <ParameterList>)?> <body:BlockStatementOrSemiColon> <r:@R> => {
-        let returns = returns.unwrap_or(Vec::new());
+    <returns:(returns ParameterList)?> <body:BlockStatementOrSemiColon> <r:@R> => {
+        let (return_not_returns, returns) = returns.unwrap_or((None, Vec::new()));
 
         Box::new(FunctionDefinition{
             doc,
@@ -513,6 +519,7 @@ ConstructorDefinition: Box<FunctionDefinition> = {
             name_loc: Loc(file_no, nl, nr),
             params,
             attributes,
+            return_not_returns,
             returns,
             body,
         })
@@ -522,8 +529,8 @@ ConstructorDefinition: Box<FunctionDefinition> = {
 FunctionDefinition: Box<FunctionDefinition> = {
     <doc:DocComments> <l:@L> "function" <nl:@L> <name:Identifier> <nr:@R> <params:ParameterList>
     <attributes:FunctionAttribute*>
-    <returns:("returns" <ParameterList>)?> <body:BlockStatementOrSemiColon> <r:@R> => {
-        let returns = returns.unwrap_or(Vec::new());
+    <returns:(returns ParameterList)?> <body:BlockStatementOrSemiColon> <r:@R> => {
+        let (return_not_returns, returns) = returns.unwrap_or((None, Vec::new()));
 
         Box::new(FunctionDefinition{
             doc,
@@ -533,6 +540,7 @@ FunctionDefinition: Box<FunctionDefinition> = {
             name_loc: Loc(file_no, nl, nr),
             params,
             attributes,
+            return_not_returns,
             returns,
             body,
         })
@@ -552,6 +560,7 @@ FunctionDefinition: Box<FunctionDefinition> = {
                     name_loc: Loc(file_no, l, r),
                     params,
                     attributes,
+                    return_not_returns: None,
                     returns,
                     body,
                 })

File diff suppressed because it is too large
+ 285 - 278
src/parser/solidity.rs


+ 8 - 0
src/sema/functions.rs

@@ -85,6 +85,14 @@ pub fn contract_function(
         }
     }
 
+    if let Some(loc) = func.return_not_returns {
+        ns.diagnostics.push(Diagnostic::error(
+            loc,
+            "‘return’ unexpected. Did you mean ‘returns’?".to_string(),
+        ));
+        success = false;
+    }
+
     let mut mutability: Option<pt::StateMutability> = None;
     let mut visibility: Option<pt::Visibility> = None;
     let mut is_virtual: Option<pt::Loc> = None;

+ 17 - 0
tests/substrate_tests/functions.rs

@@ -1188,3 +1188,20 @@ fn global_functions() {
 
     runtime.function("test", Vec::new());
 }
+
+#[test]
+fn return_not_returns() {
+    let ns = parse_and_resolve(
+        "contract test {
+            function bar() public pure return (int64) {
+                return 1;
+            }
+        }",
+        Target::Substrate,
+    );
+
+    assert_eq!(
+        first_error(ns.diagnostics),
+        "‘return’ unexpected. Did you mean ‘returns’?"
+    );
+}

Some files were not shown because too many files changed in this diff