Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parser recovery for let statements #4925

Merged
merged 10 commits into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions sway-ast/src/statement.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use sway_error::handler::ErrorEmitted;

use crate::priv_prelude::*;

#[allow(clippy::large_enum_variant)]
Expand All @@ -9,6 +11,8 @@ pub enum Statement {
expr: Expr,
semicolon_token_opt: Option<SemicolonToken>,
},
// to handle parser recovery: Error represents an unknown statement
Error(Box<[Span]>, #[serde(skip_serializing)] ErrorEmitted),
}

#[derive(Clone, Debug, Serialize)]
Expand All @@ -33,6 +37,7 @@ impl Spanned for Statement {
None => expr.span(),
Some(semicolon_token) => Span::join(expr.span(), semicolon_token.span()),
},
Statement::Error(spans, _) => Span::join_all(spans.iter().cloned()),
}
}
}
Expand Down
56 changes: 39 additions & 17 deletions sway-core/src/control_flow_analysis/analyze_return_paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,29 @@ impl<'cfg> ControlFlowGraph<'cfg> {
pub(crate) fn construct_return_path_graph<'eng: 'cfg>(
engines: &'eng Engines,
module_nodes: &[ty::TyAstNode],
) -> Result<Self, CompileError> {
) -> Result<Self, Vec<CompileError>> {
let mut errors = vec![];

let mut graph = ControlFlowGraph::default();
// do a depth first traversal and cover individual inner ast nodes
let mut leaves = vec![];
for ast_entrypoint in module_nodes {
let l_leaves = connect_node(engines, ast_entrypoint, &mut graph, &leaves)?;
if let NodeConnection::NextStep(nodes) = l_leaves {
leaves = nodes;
match connect_node(engines, ast_entrypoint, &mut graph, &leaves) {
Ok(NodeConnection::NextStep(nodes)) => {
leaves = nodes;
}
Ok(_) => {}
Err(mut e) => {
errors.append(&mut e);
}
}
}
Ok(graph)

if !errors.is_empty() {
Err(errors)
} else {
Ok(graph)
}
}

/// This function looks through the control flow graph and ensures that all paths that are
Expand Down Expand Up @@ -130,7 +142,7 @@ fn connect_node<'eng: 'cfg, 'cfg>(
node: &ty::TyAstNode,
graph: &mut ControlFlowGraph<'cfg>,
leaves: &[NodeIndex],
) -> Result<NodeConnection, CompileError> {
) -> Result<NodeConnection, Vec<CompileError>> {
match &node.content {
ty::TyAstNodeContent::Expression(ty::TyExpression {
expression: ty::TyExpressionVariant::Return(..),
Expand Down Expand Up @@ -169,6 +181,7 @@ fn connect_node<'eng: 'cfg, 'cfg>(
ty::TyAstNodeContent::Declaration(decl) => Ok(NodeConnection::NextStep(
connect_declaration(engines, node, decl, graph, leaves)?,
)),
ty::TyAstNodeContent::Error(_, _) => Ok(NodeConnection::NextStep(vec![])),
}
}

Expand All @@ -178,7 +191,7 @@ fn connect_declaration<'eng: 'cfg, 'cfg>(
decl: &ty::TyDecl,
graph: &mut ControlFlowGraph<'cfg>,
leaves: &[NodeIndex],
) -> Result<Vec<NodeIndex>, CompileError> {
) -> Result<Vec<NodeIndex>, Vec<CompileError>> {
let decl_engine = engines.de();
match decl {
ty::TyDecl::TraitDecl(_)
Expand Down Expand Up @@ -232,7 +245,7 @@ fn connect_impl_trait<'eng: 'cfg, 'cfg>(
graph: &mut ControlFlowGraph<'cfg>,
items: &[TyImplItem],
entry_node: NodeIndex,
) -> Result<(), CompileError> {
) -> Result<(), Vec<CompileError>> {
let decl_engine = engines.de();
let mut methods_and_indexes = vec![];
// insert method declarations into the graph
Expand Down Expand Up @@ -280,7 +293,7 @@ fn connect_typed_fn_decl<'eng: 'cfg, 'cfg>(
fn_decl: &ty::TyFunctionDecl,
graph: &mut ControlFlowGraph<'cfg>,
entry_node: NodeIndex,
) -> Result<(), CompileError> {
) -> Result<(), Vec<CompileError>> {
let type_engine = engines.te();
let fn_exit_node = graph.add_node(format!("\"{}\" fn exit", fn_decl.name.as_str()).into());
let return_nodes =
Expand All @@ -307,17 +320,26 @@ fn depth_first_insertion_code_block<'eng: 'cfg, 'cfg>(
node_content: &ty::TyCodeBlock,
graph: &mut ControlFlowGraph<'cfg>,
leaves: &[NodeIndex],
) -> Result<ReturnStatementNodes, CompileError> {
) -> Result<ReturnStatementNodes, Vec<CompileError>> {
let mut errors = vec![];

let mut leaves = leaves.to_vec();
let mut return_nodes = vec![];
for node in node_content.contents.iter() {
let this_node = connect_node(engines, node, graph, &leaves)?;
match this_node {
NodeConnection::NextStep(nodes) => leaves = nodes,
NodeConnection::Return(node) => {
return_nodes.push(node);
}
match connect_node(engines, node, graph, &leaves) {
Ok(this_node) => match this_node {
NodeConnection::NextStep(nodes) => leaves = nodes,
NodeConnection::Return(node) => {
return_nodes.push(node);
}
},
Err(mut e) => errors.append(&mut e),
}
}
Ok(return_nodes)

if !errors.is_empty() {
Err(errors)
} else {
Ok(return_nodes)
}
}
8 changes: 7 additions & 1 deletion sway-core/src/control_flow_analysis/dead_code_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
decl_engine::*,
language::{
parsed::TreeType,
ty::{self, TyImplItem},
ty::{self, TyAstNodeContent, TyImplItem},
CallPath, Visibility,
},
transform::{self, AttributesMap},
Expand Down Expand Up @@ -426,6 +426,7 @@ fn connect_node<'eng: 'cfg, 'cfg>(
exit_node,
)
}
ty::TyAstNodeContent::Error(_, _) => (vec![], None),
})
}

Expand Down Expand Up @@ -2099,6 +2100,10 @@ fn construct_dead_code_warning_from_node(
span: span.clone(),
warning_content: Warning::UnreachableCode,
},
ty::TyAstNode {
content: TyAstNodeContent::Error(_, _),
..
} => return None,
})
}

Expand Down Expand Up @@ -2258,6 +2263,7 @@ fn allow_dead_code_ast_node(decl_engine: &DeclEngine, node: &ty::TyAstNode) -> b
ty::TyAstNodeContent::Expression(_) => false,
ty::TyAstNodeContent::ImplicitReturnExpression(_) => false,
ty::TyAstNodeContent::SideEffect(_) => false,
ty::TyAstNodeContent::Error(_, _) => false,
}
}

Expand Down
7 changes: 5 additions & 2 deletions sway-core/src/ir_generation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub fn compile_program<'eng>(
program: &ty::TyProgram,
include_tests: bool,
engines: &'eng Engines,
) -> Result<Context<'eng>, CompileError> {
) -> Result<Context<'eng>, Vec<CompileError>> {
let declaration_engine = engines.de();

let test_fns = match include_tests {
Expand Down Expand Up @@ -101,6 +101,9 @@ pub fn compile_program<'eng>(
//println!("{ctx}");

ctx.verify().map_err(|ir_error: sway_ir::IrError| {
CompileError::InternalOwned(ir_error.to_string(), Span::dummy())
vec![CompileError::InternalOwned(
ir_error.to_string(),
Span::dummy(),
)]
})
}
51 changes: 29 additions & 22 deletions sway-core/src/ir_generation/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,21 @@ pub(super) fn compile_script(
logged_types_map: &HashMap<TypeId, LogId>,
messages_types_map: &HashMap<TypeId, MessageId>,
test_fns: &[(ty::TyFunctionDecl, DeclRefFunction)],
) -> Result<Module, CompileError> {
) -> Result<Module, Vec<CompileError>> {
println!("1");
let module = Module::new(context, Kind::Script);
let mut md_mgr = MetadataManager::default();

compile_constants(engines, context, &mut md_mgr, module, namespace)?;
compile_constants(engines, context, &mut md_mgr, module, namespace).map_err(|err| vec![err])?;
compile_declarations(
engines,
context,
&mut md_mgr,
module,
namespace,
declarations,
)?;
)
.map_err(|err| vec![err])?;
compile_entry_function(
engines,
context,
Expand Down Expand Up @@ -76,19 +78,20 @@ pub(super) fn compile_predicate(
logged_types: &HashMap<TypeId, LogId>,
messages_types: &HashMap<TypeId, MessageId>,
test_fns: &[(ty::TyFunctionDecl, DeclRefFunction)],
) -> Result<Module, CompileError> {
) -> Result<Module, Vec<CompileError>> {
let module = Module::new(context, Kind::Predicate);
let mut md_mgr = MetadataManager::default();

compile_constants(engines, context, &mut md_mgr, module, namespace)?;
compile_constants(engines, context, &mut md_mgr, module, namespace).map_err(|err| vec![err])?;
compile_declarations(
engines,
context,
&mut md_mgr,
module,
namespace,
declarations,
)?;
)
.map_err(|err| vec![err])?;
compile_entry_function(
engines,
context,
Expand Down Expand Up @@ -122,19 +125,20 @@ pub(super) fn compile_contract(
messages_types_map: &HashMap<TypeId, MessageId>,
test_fns: &[(ty::TyFunctionDecl, DeclRefFunction)],
engines: &Engines,
) -> Result<Module, CompileError> {
) -> Result<Module, Vec<CompileError>> {
let module = Module::new(context, Kind::Contract);
let mut md_mgr = MetadataManager::default();

compile_constants(engines, context, &mut md_mgr, module, namespace)?;
compile_constants(engines, context, &mut md_mgr, module, namespace).map_err(|err| vec![err])?;
compile_declarations(
engines,
context,
&mut md_mgr,
module,
namespace,
declarations,
)?;
)
.map_err(|err| vec![err])?;
for decl in abi_entries {
compile_abi_method(
context,
Expand Down Expand Up @@ -168,19 +172,20 @@ pub(super) fn compile_library(
logged_types_map: &HashMap<TypeId, LogId>,
messages_types_map: &HashMap<TypeId, MessageId>,
test_fns: &[(ty::TyFunctionDecl, DeclRefFunction)],
) -> Result<Module, CompileError> {
) -> Result<Module, Vec<CompileError>> {
let module = Module::new(context, Kind::Library);
let mut md_mgr = MetadataManager::default();

compile_constants(engines, context, &mut md_mgr, module, namespace)?;
compile_constants(engines, context, &mut md_mgr, module, namespace).map_err(|err| vec![err])?;
compile_declarations(
engines,
context,
&mut md_mgr,
module,
namespace,
declarations,
)?;
)
.map_err(|err| vec![err])?;
compile_tests(
engines,
context,
Expand Down Expand Up @@ -311,7 +316,7 @@ pub(super) fn compile_function(
messages_types_map: &HashMap<TypeId, MessageId>,
is_entry: bool,
test_decl_ref: Option<DeclRefFunction>,
) -> Result<Option<Function>, CompileError> {
) -> Result<Option<Function>, Vec<CompileError>> {
// Currently monomorphization of generics is inlined into main() and the functions with generic
// args are still present in the AST declarations, but they can be ignored.
if !ast_fn_decl.type_parameters.is_empty() {
Expand Down Expand Up @@ -343,7 +348,7 @@ pub(super) fn compile_entry_function(
logged_types_map: &HashMap<TypeId, LogId>,
messages_types_map: &HashMap<TypeId, MessageId>,
test_decl_ref: Option<DeclRefFunction>,
) -> Result<Function, CompileError> {
) -> Result<Function, Vec<CompileError>> {
let is_entry = true;
compile_function(
engines,
Expand All @@ -368,7 +373,7 @@ pub(super) fn compile_tests(
logged_types_map: &HashMap<TypeId, LogId>,
messages_types_map: &HashMap<TypeId, MessageId>,
test_fns: &[(ty::TyFunctionDecl, DeclRefFunction)],
) -> Result<Vec<Function>, CompileError> {
) -> Result<Vec<Function>, Vec<CompileError>> {
test_fns
.iter()
.map(|(ast_fn_decl, decl_ref)| {
Expand Down Expand Up @@ -398,7 +403,7 @@ fn compile_fn(
logged_types_map: &HashMap<TypeId, LogId>,
messages_types_map: &HashMap<TypeId, MessageId>,
test_decl_ref: Option<DeclRefFunction>,
) -> Result<Function, CompileError> {
) -> Result<Function, Vec<CompileError>> {
let type_engine = engines.te();
let decl_engine = engines.de();

Expand Down Expand Up @@ -439,15 +444,17 @@ fn compile_fn(
)
})
})
.collect::<Result<Vec<_>, CompileError>>()?;
.collect::<Result<Vec<_>, CompileError>>()
.map_err(|err| vec![err])?;

let ret_type = convert_resolved_typeid(
type_engine,
decl_engine,
context,
&return_type.type_id,
&return_type.span,
)?;
)
.map_err(|err| vec![err])?;

let span_md_idx = md_mgr.span_to_md(context, span);
let storage_md_idx = md_mgr.purity_to_md(context, *purity);
Expand Down Expand Up @@ -529,7 +536,7 @@ fn compile_abi_method(
logged_types_map: &HashMap<TypeId, LogId>,
messages_types_map: &HashMap<TypeId, MessageId>,
engines: &Engines,
) -> Result<Function, CompileError> {
) -> Result<Function, Vec<CompileError>> {
// Use the error from .to_fn_selector_value() if possible, else make an CompileError::Internal.
let handler = Handler::default();
let get_selector_result = ast_fn_decl.to_fn_selector_value(&handler, engines);
Expand All @@ -538,15 +545,15 @@ fn compile_abi_method(
Some(selector) => selector,
None => {
return if !errors.is_empty() {
Err(errors[0].clone())
Err(vec![errors[0].clone()])
} else {
Err(CompileError::InternalOwned(
Err(vec![CompileError::InternalOwned(
format!(
"Cannot generate selector for ABI method: {}",
ast_fn_decl.name.as_str()
),
ast_fn_decl.name.span(),
))
)])
};
}
};
Expand Down
3 changes: 3 additions & 0 deletions sway-core/src/ir_generation/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,9 @@ fn const_eval_codeblock(
ty::TyAstNodeContent::SideEffect(_) => Err(ConstEvalError::CannotBeEvaluatedToConst {
span: ast_node.span.clone(),
}),
ty::TyAstNodeContent::Error(_, _) => {
unreachable!("error node found when generating IR");
}
};

if result.is_err() {
Expand Down
Loading
Loading