diff --git a/external-crates/move/crates/move-compiler/src/expansion/translate.rs b/external-crates/move/crates/move-compiler/src/expansion/translate.rs index 08324d3ad2138e..093a28e8f9af01 100644 --- a/external-crates/move/crates/move-compiler/src/expansion/translate.rs +++ b/external-crates/move/crates/move-compiler/src/expansion/translate.rs @@ -1704,7 +1704,14 @@ fn module_use( } } } - P::ModuleUse::Partial { .. } => (), // no members or aliases to process + P::ModuleUse::Partial { .. } => { + let mident = module_ident(&mut context.defn_context, in_mident); + if !context.defn_context.module_members.contains_key(&mident) { + context.env().add_diag(unbound_module(&mident)); + return; + }; + add_module_alias!(mident, mident.value.module.0) + } } } diff --git a/external-crates/move/crates/move-compiler/src/parser/syntax.rs b/external-crates/move/crates/move-compiler/src/parser/syntax.rs index 9b60749e2da188..f59f9887b326e6 100644 --- a/external-crates/move/crates/move-compiler/src/parser/syntax.rs +++ b/external-crates/move/crates/move-compiler/src/parser/syntax.rs @@ -1499,12 +1499,8 @@ fn parse_sequence(context: &mut Context) -> Result> { let mut uses = vec![]; while context.tokens.peek() == Tok::Use { let start_loc = context.tokens.start_loc(); - uses.push(parse_use_decl( - vec![], - start_loc, - Modifiers::empty(), - context, - )?); + let tmp = parse_use_decl(vec![], start_loc, Modifiers::empty(), context)?; + uses.push(tmp); } let mut seq: Vec = vec![]; @@ -4137,7 +4133,7 @@ fn parse_use_decl( start_loc, " after an address in a use declaration", ) { - context.env.add_diag(*diag); + context.add_diag(*diag); Use::Partial { package: address, colon_colon: None, @@ -4159,6 +4155,9 @@ fn parse_use_decl( let (name, _, use_) = parse_use_module(ctxt)?; Ok((name, use_)) }; + // add `;` to stop set to limit number of eaten tokens if the list is parsed + // incorrectly + context.stop_set.add(Tok::Semicolon); let use_decls = parse_comma_list( context, Tok::LBrace, @@ -4167,7 +4166,7 @@ fn parse_use_decl( parse_inner, "a module use clause", ); - if use_decls.is_empty() && module_uses_to_parse_exist { + let use_ = if use_decls.is_empty() && module_uses_to_parse_exist { // we failed to parse a non-empty list Use::Partial { package: address, @@ -4176,35 +4175,49 @@ fn parse_use_decl( } } else { Use::NestedModuleUses(address, use_decls) - } + }; + context.stop_set.remove(Tok::Semicolon); + use_ } - _ => match parse_use_module(context) { - Ok((name, end_loc, use_)) => { - let loc = - make_loc(context.tokens.file_hash(), address_start_loc, end_loc); - let module_ident = sp( - loc, - ModuleIdent_ { - address, - module: name, - }, - ); - Use::ModuleUse(module_ident, use_) - } - Err(diag) => { - context.env.add_diag(*diag); - Use::Partial { - package: address, - colon_colon: Some(colon_colon_loc), - opening_brace: None, + _ => { + // add `;` to stop set to limit number of eaten tokens if the module use is + // parsed incorrectly + context.stop_set.add(Tok::Semicolon); + let use_ = match parse_use_module(context) { + Ok((name, end_loc, use_)) => { + let loc = make_loc( + context.tokens.file_hash(), + address_start_loc, + end_loc, + ); + let module_ident = sp( + loc, + ModuleIdent_ { + address, + module: name, + }, + ); + Use::ModuleUse(module_ident, use_) } - } - }, + Err(diag) => { + context.add_diag(*diag); + Use::Partial { + package: address, + colon_colon: Some(colon_colon_loc), + opening_brace: None, + } + } + }; + context.stop_set.remove(Tok::Semicolon); + use_ + } } } } }; - consume_token(context.tokens, Tok::Semicolon)?; + if let Err(diag) = consume_token(context.tokens, Tok::Semicolon) { + context.add_diag(*diag); + } let end_loc = context.tokens.previous_end_loc(); let loc = make_loc(context.tokens.file_hash(), start_loc, end_loc); Ok(UseDecl { @@ -4229,7 +4242,7 @@ fn parse_use_module( (None, Tok::ColonColon) => { let colon_colon_loc = context.tokens.current_token_loc(); if let Err(diag) = consume_token(context.tokens, Tok::ColonColon) { - context.env.add_diag(*diag); + context.add_diag(*diag); ModuleUse::Partial { colon_colon: None, opening_brace: None, @@ -4267,7 +4280,7 @@ fn parse_use_module( _ => match parse_use_member(context) { Ok(m) => ModuleUse::Members(vec![m]), Err(diag) => { - context.env.add_diag(*diag); + context.add_diag(*diag); ModuleUse::Partial { colon_colon: Some(colon_colon_loc), opening_brace: None, diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/ide_mode/use_incomplete.exp b/external-crates/move/crates/move-compiler/tests/move_2024/ide_mode/use_incomplete.exp new file mode 100644 index 00000000000000..0e34cb2cfccff6 --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/ide_mode/use_incomplete.exp @@ -0,0 +1,77 @@ +error[E01002]: unexpected token + ┌─ tests/move_2024/ide_mode/use_incomplete.move:5:9 + │ +5 │ let _tmp = 42; // reset parser to see if the next line compiles + │ ^^^ + │ │ + │ Unexpected 'let' + │ Expected an identifier + +error[E01002]: unexpected token + ┌─ tests/move_2024/ide_mode/use_incomplete.move:11:9 + │ +11 │ let _tmp = 42; // reset parser to see if the next line compiles + │ ^^^ + │ │ + │ Unexpected 'let' + │ Expected ',' or '}' + +error[E01002]: unexpected token + ┌─ tests/move_2024/ide_mode/use_incomplete.move:11:22 + │ +10 │ use a::m2::{foo + │ - To match this '{' +11 │ let _tmp = 42; // reset parser to see if the next line compiles + │ ^ Expected '}' + +error[E01002]: unexpected token + ┌─ tests/move_2024/ide_mode/use_incomplete.move:17:9 + │ +17 │ let _tmp = 42; // reset parser to see if the next lines compile + │ ^^^ + │ │ + │ Unexpected 'let' + │ Expected ',' or '}' + +error[E01002]: unexpected token + ┌─ tests/move_2024/ide_mode/use_incomplete.move:17:22 + │ +16 │ use a::m2::{foo, bar + │ - To match this '{' +17 │ let _tmp = 42; // reset parser to see if the next lines compile + │ ^ Expected '}' + +error[E01002]: unexpected token + ┌─ tests/move_2024/ide_mode/use_incomplete.move:24:9 + │ +24 │ let _tmp = 42; // reset parser to see if the next lines compile + │ ^^^ + │ │ + │ Unexpected 'let' + │ Expected ',' or '}' + +error[E01002]: unexpected token + ┌─ tests/move_2024/ide_mode/use_incomplete.move:24:22 + │ +23 │ use a::{m2::{foo, bar + │ - To match this '{' +24 │ let _tmp = 42; // reset parser to see if the next lines compile + │ ^ Expected '}' + +error[E01002]: unexpected token + ┌─ tests/move_2024/ide_mode/use_incomplete.move:32:9 + │ +32 │ let _tmp = 42; // reset parser to see if the next lines compile + │ ^^^ + │ │ + │ Unexpected 'let' + │ Expected ',' or '}' + +error[E01002]: unexpected token + ┌─ tests/move_2024/ide_mode/use_incomplete.move:32:22 + │ +31 │ use a::{m2::{foo, bar}, m3 + │ - To match this '{' +32 │ let _tmp = 42; // reset parser to see if the next lines compile + │ ^ Expected '}' + diff --git a/external-crates/move/crates/move-compiler/tests/move_2024/ide_mode/use_incomplete.move b/external-crates/move/crates/move-compiler/tests/move_2024/ide_mode/use_incomplete.move new file mode 100644 index 00000000000000..e0c8e30aafe0da --- /dev/null +++ b/external-crates/move/crates/move-compiler/tests/move_2024/ide_mode/use_incomplete.move @@ -0,0 +1,49 @@ +module a::m { + + public fun test1() { + use a::m2:: + let _tmp = 42; // reset parser to see if the next line compiles + m2::foo(); + } + + public fun test2() { + use a::m2::{foo + let _tmp = 42; // reset parser to see if the next line compiles + foo(); + } + + public fun test3() { + use a::m2::{foo, bar + let _tmp = 42; // reset parser to see if the next lines compile + foo(); + bar(); + } + + public fun test4() { + use a::{m2::{foo, bar + let _tmp = 42; // reset parser to see if the next lines compile + foo(); + bar(); + + } + + public fun test5() { + use a::{m2::{foo, bar}, m3 + let _tmp = 42; // reset parser to see if the next lines compile + m3::baz(); + foo(); + bar(); + } +} + +module a::m2 { + + public fun foo() {} + + public fun bar() {} +} + +module a::m3 { + + public fun baz() {} +} diff --git a/external-crates/move/crates/move-compiler/tests/move_check/parser/use_module_member_invalid_missing_close_brace.exp b/external-crates/move/crates/move-compiler/tests/move_check/parser/use_module_member_invalid_missing_close_brace.exp index 2c8419ace14a89..a3c5d6ba63037d 100644 --- a/external-crates/move/crates/move-compiler/tests/move_check/parser/use_module_member_invalid_missing_close_brace.exp +++ b/external-crates/move/crates/move-compiler/tests/move_check/parser/use_module_member_invalid_missing_close_brace.exp @@ -1,16 +1,16 @@ error[E01002]: unexpected token ┌─ tests/move_check/parser/use_module_member_invalid_missing_close_brace.move:6:5 │ -4 │ use 0x1::X::{S as XS - │ - To match this '{' +4 │ use 0x42::M::{S as XS + │ - To match this '{' 5 │ -6 │ fun foo() { +6 │ fun foo() {} │ ^ Expected '}' error[E01002]: unexpected token ┌─ tests/move_check/parser/use_module_member_invalid_missing_close_brace.move:6:5 │ -6 │ fun foo() { +6 │ fun foo() {} │ ^^^ │ │ │ Unexpected 'fun' diff --git a/external-crates/move/crates/move-compiler/tests/move_check/parser/use_module_member_invalid_missing_close_brace.move b/external-crates/move/crates/move-compiler/tests/move_check/parser/use_module_member_invalid_missing_close_brace.move index ed776d516fbd61..022ba96b63c1f7 100644 --- a/external-crates/move/crates/move-compiler/tests/move_check/parser/use_module_member_invalid_missing_close_brace.move +++ b/external-crates/move/crates/move-compiler/tests/move_check/parser/use_module_member_invalid_missing_close_brace.move @@ -1,9 +1,11 @@ module 0x42::M { - use 0x1::X::{S as XS + use 0x42::M::{S as XS - fun foo() { + fun foo() {} - } + struct S has drop {} + + fun bar(_p: XS) {} } diff --git a/external-crates/move/crates/move-compiler/tests/move_check/parser/use_module_member_invalid_missing_semicolon.exp b/external-crates/move/crates/move-compiler/tests/move_check/parser/use_module_member_invalid_missing_semicolon.exp index b7adf60971e580..7cfa235226b669 100644 --- a/external-crates/move/crates/move-compiler/tests/move_check/parser/use_module_member_invalid_missing_semicolon.exp +++ b/external-crates/move/crates/move-compiler/tests/move_check/parser/use_module_member_invalid_missing_semicolon.exp @@ -1,9 +1,9 @@ error[E01002]: unexpected token - ┌─ tests/move_check/parser/use_module_member_invalid_missing_semicolon.move:5:1 + ┌─ tests/move_check/parser/use_module_member_invalid_missing_semicolon.move:6:5 │ -5 │ } - │ ^ - │ │ - │ Unexpected '}' - │ Expected ';' +6 │ fun foo() {} + │ ^^^ + │ │ + │ Unexpected 'fun' + │ Expected ';' diff --git a/external-crates/move/crates/move-compiler/tests/move_check/parser/use_module_member_invalid_missing_semicolon.move b/external-crates/move/crates/move-compiler/tests/move_check/parser/use_module_member_invalid_missing_semicolon.move index 645abec93ca363..c1280790461feb 100644 --- a/external-crates/move/crates/move-compiler/tests/move_check/parser/use_module_member_invalid_missing_semicolon.move +++ b/external-crates/move/crates/move-compiler/tests/move_check/parser/use_module_member_invalid_missing_semicolon.move @@ -1,5 +1,11 @@ module 0x42::M { - use 0x1::X::{S as XS,} + use 0x42::M::{S as XS,} + + fun foo() {} + + struct S has drop {} + + fun bar(_p: XS) {} }