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

The compiler checks for exhaustive match arms in match expressions. #701

Merged
merged 65 commits into from
Mar 22, 2022
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
27086cc
Test case.
Jan 25, 2022
55eaf2a
Remove unused expression.
Jan 25, 2022
33ae5d9
Introduce the MatchExp as a wrapper for IfExp.
Jan 25, 2022
4f0ae3a
Add generated names to this PR.
Jan 26, 2022
1cc7e1c
Fix uncompleted change.
Jan 26, 2022
ffbc94f
Edit parsing mechanism to allow expressions the possibility of declar…
Feb 1, 2022
69abbca
Merge with master.
Feb 1, 2022
841cca3
Fix license information.
Feb 1, 2022
168fe43
Clippy suggestions.
Feb 1, 2022
c641ced
Use intermediate variable in match expressions.
Feb 1, 2022
4a2891d
Update description of desugaring process.
Feb 1, 2022
554b8a9
Exhaustivity checking works on integers
Feb 1, 2022
c4cbb63
Exhaustivity check works for tuples.
Feb 1, 2022
50726ab
Merge with master.
Feb 8, 2022
9b1515a
Code review suggestions.
Feb 8, 2022
d6f4005
Rebrand to usefulness.
Feb 8, 2022
db53451
Compute specialized matrix algorithm.
Feb 9, 2022
71e5373
WIP
Feb 10, 2022
d742196
Exhaustivity works in basic cases.
Feb 10, 2022
511f53a
WIP
Feb 11, 2022
8f18c67
WIP
Feb 11, 2022
70a5b80
Add error messages.
Feb 11, 2022
e8ed617
Add some documentation.
Feb 11, 2022
9b782ac
Misc cleanup items.
Feb 11, 2022
9b29c25
Finding unimplemented patterns works for basic integers.
Feb 14, 2022
6fbe5c4
Fix small bug.
Feb 14, 2022
6d084ec
Display max and min instead of big numbers.
Feb 14, 2022
5b32bcd
WIP working on debugging
Feb 15, 2022
16baee7
Merge with master.
Feb 22, 2022
e22119a
Working for tuples.
Feb 22, 2022
f3f0d58
More stuff for tuples.
Feb 23, 2022
402e10b
Structs work.
Feb 23, 2022
916bc0a
Nested structures work.
Feb 23, 2022
1d3fa3f
Better display for Structs.
Feb 23, 2022
d6ba815
Merge remote-tracking branch 'origin/master' into emilyaherbert-581/e…
Feb 23, 2022
db434d8
Fix merge conflicts.
Feb 23, 2022
a76716e
Fix broken tests.
Feb 23, 2022
8266f4e
Merge remote-tracking branch 'origin/master' into emilyaherbert-581/e…
Feb 23, 2022
237028c
Some docstrings stuff.
Feb 23, 2022
9748d8f
More docstring stuff.
Feb 23, 2022
f48e8ad
More docstring stuff.
Feb 23, 2022
3c195f7
More docstring stuff.
Feb 24, 2022
5794b9b
WIP
Feb 24, 2022
e76585d
Move usefulness to its own dir.
Feb 24, 2022
0a28ae0
Merge remote-tracking branch 'origin/master' into emilyaherbert-581/e…
Feb 24, 2022
12c31d0
Fix clippy warning.
Feb 24, 2022
e3561fd
Last of documentation.
Feb 24, 2022
cd78146
Merge remote-tracking branch 'origin/master' into emilyaherbert-581/e…
Feb 24, 2022
8c1c89a
Fix test case pointing to too advanced std.
Feb 24, 2022
e544742
Merge remote-tracking branch 'origin/master' into emilyaherbert-581/e…
Feb 25, 2022
ceec0d1
Condense internal compiler error messages to one error type.
Feb 25, 2022
41210e8
Merge with master.
Mar 1, 2022
15fbf4d
Remove vscode from gitignore.
Mar 1, 2022
1a0056c
Merge with master.
Mar 8, 2022
2651a63
Feedback.
Mar 8, 2022
8ce4d72
Merge remote-tracking branch 'origin/master' into emilyaherbert-581/e…
Mar 8, 2022
2910a06
Improve test cases.
Mar 8, 2022
44d6c77
other test case.
Mar 8, 2022
a26939f
Merge with master.
Mar 16, 2022
ee4aaa3
Clippy issues.
Mar 16, 2022
743dfe0
Merge branch 'master' into emilyaherbert-581/exhaustive-pattern-matches
adlerjohn Mar 19, 2022
f7c5515
Merge with master.
Mar 22, 2022
fa1ac15
Merge branch 'emilyaherbert-581/exhaustive-pattern-matches' of github…
Mar 22, 2022
98a3dc2
Merge branch 'master' into emilyaherbert-581/exhaustive-pattern-matches
emilyaherbert Mar 22, 2022
ed25397
Update sway-core/Cargo.toml
emilyaherbert Mar 22, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions sway-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ sway-ir = { version = "0.3.3", path = "../sway-ir" }
sway-types = { version = "0.3.3", path = "../sway-types" }
generational-arena = "0.2"
thiserror = "1.0"
nanoid = "0.4.0"

[[bin]]
name = "selector-debug"
Expand Down
1 change: 1 addition & 0 deletions sway-core/src/asm_generation/from_ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1385,6 +1385,7 @@ mod tests {
print_intermediate_asm: false,
print_finalized_asm: false,
print_ir: false,
generated_names: std::sync::Arc::new(std::sync::Mutex::new(vec![])),
},
);

Expand Down
7 changes: 6 additions & 1 deletion sway-core/src/build_config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::{path::PathBuf, sync::Arc};
use std::{
path::PathBuf,
sync::{Arc, Mutex},
};

/// Configuration for the overall build and compilation process.
#[derive(Clone)]
Expand All @@ -10,6 +13,7 @@ pub struct BuildConfig {
pub(crate) print_intermediate_asm: bool,
pub(crate) print_finalized_asm: bool,
pub(crate) print_ir: bool,
pub(crate) generated_names: Arc<Mutex<Vec<&'static str>>>,
}

impl BuildConfig {
Expand All @@ -29,6 +33,7 @@ impl BuildConfig {
print_intermediate_asm: false,
print_finalized_asm: false,
print_ir: false,
generated_names: Arc::new(Mutex::new(vec![])),
}
}

Expand Down
13 changes: 13 additions & 0 deletions sway-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::{
parser::Rule,
style::{to_screaming_snake_case, to_snake_case, to_upper_camel_case},
type_engine::*,
VariableDeclaration,
};
use sway_types::{ident::Ident, span::Span};

Expand Down Expand Up @@ -69,6 +70,12 @@ pub(crate) fn ok<T>(
}
}

#[derive(Debug, Clone)]
pub struct ParseResult<T> {
emilyaherbert marked this conversation as resolved.
Show resolved Hide resolved
pub var_decls: Vec<VariableDeclaration>,
pub value: T,
}

#[derive(Debug, Clone)]
pub struct CompileResult<T> {
pub value: Option<T>,
Expand Down Expand Up @@ -382,6 +389,8 @@ pub enum CompileError {
span: Span,
err: pest::error::Error<Rule>,
},
#[error("Error parsing input: {err:?}")]
ParseError { span: Span, err: String },
#[error(
"Invalid top-level item: {0:?}. A program should consist of a contract, script, or \
predicate at the top level."
Expand Down Expand Up @@ -797,6 +806,8 @@ pub enum CompileError {
"
)]
MatchWrongType { expected: TypeId, span: Span },
#[error("Non-exhaustive match expression. Try adding a catchall arm.")]
MatchExpressionNonExhaustive { span: Span },
#[error("Impure function called inside of pure function. Pure functions can only call other pure functions. Try making the surrounding function impure by prepending \"impure\" to the function declaration.")]
PureCalledImpure { span: Span },
#[error("Impure function inside of non-contract. Contract storage is only accessible from contracts.")]
Expand Down Expand Up @@ -903,6 +914,7 @@ impl CompileError {
Unimplemented(_, span) => span,
TypeError(err) => err.internal_span(),
ParseFailure { span, .. } => span,
ParseError { span, .. } => span,
InvalidTopLevelItem(_, span) => span,
Internal(_, span) => span,
InternalOwned(_, span) => span,
Expand Down Expand Up @@ -998,6 +1010,7 @@ impl CompileError {
ArrayOutOfBounds { span, .. } => span,
ShadowsOtherSymbol { span, .. } => span,
MatchWrongType { span, .. } => span,
MatchExpressionNonExhaustive { span } => span,
NotAnEnum { span, .. } => span,
PatternMatchingAlgorithmFailure(_, span) => span,
PureCalledImpure { span, .. } => span,
Expand Down
19 changes: 11 additions & 8 deletions sway-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -579,19 +579,22 @@ fn parse_root_from_pairs(
for pair in input {
match pair.as_rule() {
Rule::non_var_decl => {
let decl = check!(
let span = span::Span {
span: pair.as_span(),
path: path.clone(),
};
let decls = check!(
Declaration::parse_non_var_from_pair(pair.clone(), config),
continue,
warnings,
errors
);
parse_tree.push(AstNode {
content: AstNodeContent::Declaration(decl),
span: span::Span {
span: pair.as_span(),
path: path.clone(),
},
});
for decl in decls.into_iter() {
parse_tree.push(AstNode {
content: AstNodeContent::Declaration(decl),
span: span.clone(),
});
}
}
Rule::use_statement => {
let stmt = check!(
Expand Down
1 change: 1 addition & 0 deletions sway-core/src/optimize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1583,6 +1583,7 @@ mod tests {
print_intermediate_asm: false,
print_finalized_asm: false,
print_ir: false,
generated_names: std::sync::Arc::new(std::sync::Mutex::new(vec![])),
emilyaherbert marked this conversation as resolved.
Show resolved Hide resolved
};
TypedParseTree::type_check(
parse_tree.tree,
Expand Down
117 changes: 90 additions & 27 deletions sway-core/src/parse_tree/code_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,27 @@ impl CodeBlock {
let block_inner = block.into_inner();
let mut contents = Vec::new();
for pair in block_inner {
contents.push(match pair.as_rule() {
Rule::declaration => AstNode {
content: AstNodeContent::Declaration(check!(
let mut pair_contents: Vec<AstNode> = match pair.as_rule() {
Rule::declaration => {
let span = span::Span {
span: pair.as_span(),
path: path.clone(),
};
check!(
Declaration::parse_from_pair(pair.clone(), config),
continue,
warnings,
errors
)),
span: span::Span {
span: pair.as_span(),
path: path.clone(),
},
},
)
.into_iter()
.map(|x| AstNode {
content: AstNodeContent::Declaration(x),
span: span.clone(),
})
.collect::<Vec<_>>()
}
Rule::expr_statement => {
let evaluated_node = check!(
let evaluated_node_result = check!(
Expression::parse_from_pair(
pair.clone().into_inner().next().unwrap().clone(),
config
Expand All @@ -55,55 +61,111 @@ impl CodeBlock {
warnings,
errors
);
AstNode {
content: AstNodeContent::Expression(evaluated_node),
let mut ast_node_contents = evaluated_node_result
.var_decls
.into_iter()
emilyaherbert marked this conversation as resolved.
Show resolved Hide resolved
.map(|x| AstNode {
content: AstNodeContent::Declaration(Declaration::VariableDeclaration(
x,
)),
span: span::Span {
span: pair.as_span(),
path: path.clone(),
},
})
.collect::<Vec<_>>();
ast_node_contents.push(AstNode {
content: AstNodeContent::Expression(evaluated_node_result.value),
span: span::Span {
span: pair.as_span(),
path: path.clone(),
},
}
});
ast_node_contents
}
Rule::return_statement => {
let evaluated_node = check!(
let res_result = check!(
emilyaherbert marked this conversation as resolved.
Show resolved Hide resolved
ReturnStatement::parse_from_pair(pair.clone(), config),
continue,
warnings,
errors
);
AstNode {
content: AstNodeContent::ReturnStatement(evaluated_node),
let mut ast_node_contents = res_result
.var_decls
.into_iter()
.map(|x| AstNode {
content: AstNodeContent::Declaration(Declaration::VariableDeclaration(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this mean return statements must necessarily return a variable declaration? I'm not sure I understand this bit

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because match expressions now have the ability to create AstNodes, those nodes need to be inserted before the return statement node (the same goes for other nodes that are parsed). This bit of code is taking those new AstNodes and inserting them.

x,
)),
span: span::Span {
span: pair.as_span(),
path: path.clone(),
},
})
.collect::<Vec<_>>();
ast_node_contents.push(AstNode {
content: AstNodeContent::ReturnStatement(res_result.value),
span: span::Span {
span: pair.as_span(),
path: path.clone(),
},
}
});
ast_node_contents
}
Rule::expr => {
let res = check!(
let res_result = check!(
Expression::parse_from_pair(pair.clone(), config),
continue,
warnings,
errors
);
AstNode {
content: AstNodeContent::ImplicitReturnExpression(res.clone()),
span: res.span(),
}
let mut ast_node_contents = res_result
.var_decls
.into_iter()
.map(|x| AstNode {
content: AstNodeContent::Declaration(Declaration::VariableDeclaration(
x,
)),
span: span::Span {
span: pair.as_span(),
path: path.clone(),
},
})
.collect::<Vec<_>>();
ast_node_contents.push(AstNode {
content: AstNodeContent::ImplicitReturnExpression(res_result.value.clone()),
span: res_result.value.span(),
});
ast_node_contents
}
Rule::while_loop => {
let res = check!(
let res_result = check!(
WhileLoop::parse_from_pair(pair.clone(), config),
continue,
warnings,
errors
);
AstNode {
content: AstNodeContent::WhileLoop(res),
let mut ast_node_contents = res_result
.var_decls
.into_iter()
.map(|x| AstNode {
content: AstNodeContent::Declaration(Declaration::VariableDeclaration(
x,
)),
span: span::Span {
span: pair.as_span(),
path: path.clone(),
},
})
.collect::<Vec<_>>();
ast_node_contents.push(AstNode {
content: AstNodeContent::WhileLoop(res_result.value),
span: span::Span {
span: pair.as_span(),
path: path.clone(),
},
}
});
ast_node_contents
}
a => {
println!("In code block parsing: {:?} {:?}", a, pair.as_str());
Expand All @@ -116,7 +178,8 @@ impl CodeBlock {
));
continue;
}
})
};
contents.append(&mut pair_contents);
}

ok(
Expand Down