mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 20:28:02 +00:00
Canonicalize and constrain statement expr in purity inference mode
This commit is contained in:
parent
460fa693fd
commit
6e6382ab23
14 changed files with 197 additions and 61 deletions
|
@ -418,6 +418,7 @@ fn defn(
|
|||
expr_var: var_store.fresh(),
|
||||
pattern_vars: SendMap::default(),
|
||||
annotation: None,
|
||||
kind: crate::def::DefKind::Let,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -548,6 +549,7 @@ fn to_num_checked(symbol: Symbol, var_store: &mut VarStore, lowlevel: LowLevel)
|
|||
expr_var: record_var,
|
||||
pattern_vars: SendMap::default(),
|
||||
annotation: None,
|
||||
kind: crate::def::DefKind::Let,
|
||||
};
|
||||
|
||||
let body = LetNonRec(Box::new(def), Box::new(no_region(cont)));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
def::Def,
|
||||
def::{Def, DefKind},
|
||||
expr::{
|
||||
ClosureData, Expr, Field, OpaqueWrapFunctionData, StructAccessorData, WhenBranchPattern,
|
||||
},
|
||||
|
@ -378,6 +378,7 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
|
|||
expr_var,
|
||||
pattern_vars,
|
||||
annotation,
|
||||
kind,
|
||||
}| Def {
|
||||
loc_pattern: loc_pattern.map(|p| deep_copy_pattern_help(env, copied, p)),
|
||||
loc_expr: loc_expr.map(|e| go_help!(e)),
|
||||
|
@ -386,6 +387,10 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
|
|||
// Annotation should only be used in constraining, don't clone before
|
||||
// constraining :)
|
||||
annotation: annotation.clone(),
|
||||
kind: match kind {
|
||||
DefKind::Let => DefKind::Let,
|
||||
DefKind::Stmt(v) => DefKind::Stmt(sub!(*v)),
|
||||
},
|
||||
},
|
||||
)
|
||||
.collect(),
|
||||
|
@ -399,6 +404,7 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
|
|||
expr_var,
|
||||
pattern_vars,
|
||||
annotation,
|
||||
kind,
|
||||
} = &**def;
|
||||
let def = Def {
|
||||
loc_pattern: loc_pattern.map(|p| deep_copy_pattern_help(env, copied, p)),
|
||||
|
@ -408,6 +414,7 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
|
|||
// Annotation should only be used in constraining, don't clone before
|
||||
// constraining :)
|
||||
annotation: annotation.clone(),
|
||||
kind: *kind,
|
||||
};
|
||||
LetNonRec(Box::new(def), Box::new(body.map(|e| go_help!(e))))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Pretty-prints the canonical AST back to check our work - do things look reasonable?
|
||||
|
||||
use crate::def::Def;
|
||||
use crate::def::{Def, DefKind};
|
||||
use crate::expr::Expr::{self, *};
|
||||
use crate::expr::{
|
||||
ClosureData, DeclarationTag, Declarations, FunctionDef, OpaqueWrapFunctionData,
|
||||
|
@ -107,9 +107,13 @@ fn def<'a>(c: &Ctx, f: &'a Arena<'a>, d: &'a Def) -> DocBuilder<'a, Arena<'a>> {
|
|||
expr_var: _,
|
||||
pattern_vars: _,
|
||||
annotation: _,
|
||||
kind,
|
||||
} = d;
|
||||
|
||||
def_help(c, f, &loc_pattern.value, &loc_expr.value)
|
||||
match kind {
|
||||
DefKind::Let => def_help(c, f, &loc_pattern.value, &loc_expr.value),
|
||||
DefKind::Stmt(_) => expr(c, EPrec::Free, f, &loc_expr.value),
|
||||
}
|
||||
}
|
||||
|
||||
fn def_symbol_help<'a>(
|
||||
|
|
|
@ -10,6 +10,7 @@ use crate::annotation::IntroducedVariables;
|
|||
use crate::annotation::OwnedNamedOrAble;
|
||||
use crate::derive;
|
||||
use crate::env::Env;
|
||||
use crate::env::FxMode;
|
||||
use crate::expr::canonicalize_record;
|
||||
use crate::expr::get_lookup_symbols;
|
||||
use crate::expr::AnnotatedMark;
|
||||
|
@ -69,6 +70,7 @@ pub struct Def {
|
|||
pub expr_var: Variable,
|
||||
pub pattern_vars: SendMap<Symbol, Variable>,
|
||||
pub annotation: Option<Annotation>,
|
||||
pub kind: DefKind,
|
||||
}
|
||||
|
||||
impl Def {
|
||||
|
@ -89,6 +91,23 @@ impl Def {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum DefKind {
|
||||
/// A def that introduces identifiers
|
||||
Let,
|
||||
/// A standalone statement with an fx variable
|
||||
Stmt(Variable),
|
||||
}
|
||||
|
||||
impl DefKind {
|
||||
pub fn map_var<F: Fn(Variable) -> Variable>(self, f: F) -> Self {
|
||||
match self {
|
||||
DefKind::Let => DefKind::Let,
|
||||
DefKind::Stmt(v) => DefKind::Stmt(f(v)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Annotation {
|
||||
pub signature: Type,
|
||||
|
@ -195,22 +214,25 @@ enum PendingValueDef<'a> {
|
|||
Option<Loc<ast::TypeAnnotation<'a>>>,
|
||||
Loc<ast::StrLiteral<'a>>,
|
||||
),
|
||||
/// A standalone statement
|
||||
Stmt(&'a Loc<ast::Expr<'a>>),
|
||||
}
|
||||
|
||||
impl PendingValueDef<'_> {
|
||||
fn loc_pattern(&self) -> &Loc<Pattern> {
|
||||
fn loc_pattern(&self) -> Option<&Loc<Pattern>> {
|
||||
match self {
|
||||
PendingValueDef::AnnotationOnly(loc_pattern, _) => loc_pattern,
|
||||
PendingValueDef::Body(loc_pattern, _) => loc_pattern,
|
||||
PendingValueDef::TypedBody(_, loc_pattern, _, _) => loc_pattern,
|
||||
PendingValueDef::AnnotationOnly(loc_pattern, _) => Some(loc_pattern),
|
||||
PendingValueDef::Body(loc_pattern, _) => Some(loc_pattern),
|
||||
PendingValueDef::TypedBody(_, loc_pattern, _, _) => Some(loc_pattern),
|
||||
PendingValueDef::ImportParams {
|
||||
loc_pattern,
|
||||
symbol: _,
|
||||
variable: _,
|
||||
module_id: _,
|
||||
opt_provided: _,
|
||||
} => loc_pattern,
|
||||
PendingValueDef::IngestedFile(loc_pattern, _, _) => loc_pattern,
|
||||
} => Some(loc_pattern),
|
||||
PendingValueDef::IngestedFile(loc_pattern, _, _) => Some(loc_pattern),
|
||||
PendingValueDef::Stmt(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1189,29 +1211,29 @@ fn canonicalize_value_defs<'a>(
|
|||
let mut symbol_to_index: Vec<(IdentId, u32)> = Vec::with_capacity(pending_value_defs.len());
|
||||
|
||||
for (def_index, pending_def) in pending_value_defs.iter().enumerate() {
|
||||
let mut new_bindings = BindingsFromPattern::new(pending_def.loc_pattern()).peekable();
|
||||
if let Some(loc_pattern) = pending_def.loc_pattern() {
|
||||
let mut new_bindings = BindingsFromPattern::new(loc_pattern).peekable();
|
||||
|
||||
if new_bindings.peek().is_none() {
|
||||
env.problem(Problem::NoIdentifiersIntroduced(
|
||||
pending_def.loc_pattern().region,
|
||||
));
|
||||
}
|
||||
|
||||
for (s, r) in new_bindings {
|
||||
// store the top-level defs, used to ensure that closures won't capture them
|
||||
if let PatternType::TopLevelDef = pattern_type {
|
||||
env.top_level_symbols.insert(s);
|
||||
if new_bindings.peek().is_none() {
|
||||
env.problem(Problem::NoIdentifiersIntroduced(loc_pattern.region));
|
||||
}
|
||||
|
||||
symbols_introduced.insert(s, r);
|
||||
for (s, r) in new_bindings {
|
||||
// store the top-level defs, used to ensure that closures won't capture them
|
||||
if let PatternType::TopLevelDef = pattern_type {
|
||||
env.top_level_symbols.insert(s);
|
||||
}
|
||||
|
||||
debug_assert_eq!(env.home, s.module_id());
|
||||
debug_assert!(
|
||||
!symbol_to_index.iter().any(|(id, _)| *id == s.ident_id()),
|
||||
"{s:?}"
|
||||
);
|
||||
symbols_introduced.insert(s, r);
|
||||
|
||||
symbol_to_index.push((s.ident_id(), def_index as u32));
|
||||
debug_assert_eq!(env.home, s.module_id());
|
||||
debug_assert!(
|
||||
!symbol_to_index.iter().any(|(id, _)| *id == s.ident_id()),
|
||||
"{s:?}"
|
||||
);
|
||||
|
||||
symbol_to_index.push((s.ident_id(), def_index as u32));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2217,6 +2239,7 @@ fn single_can_def(
|
|||
expr_var: Variable,
|
||||
opt_loc_annotation: Option<Loc<crate::annotation::Annotation>>,
|
||||
pattern_vars: SendMap<Symbol, Variable>,
|
||||
kind: DefKind,
|
||||
) -> Def {
|
||||
let def_annotation = opt_loc_annotation.map(|loc_annotation| Annotation {
|
||||
signature: loc_annotation.value.typ,
|
||||
|
@ -2234,6 +2257,7 @@ fn single_can_def(
|
|||
},
|
||||
pattern_vars,
|
||||
annotation: def_annotation,
|
||||
kind,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2374,6 +2398,7 @@ fn canonicalize_pending_value_def<'a>(
|
|||
expr_var,
|
||||
Some(Loc::at(loc_ann.region, type_annotation)),
|
||||
vars_by_symbol.clone(),
|
||||
DefKind::Let,
|
||||
);
|
||||
|
||||
DefOutput {
|
||||
|
@ -2409,6 +2434,7 @@ fn canonicalize_pending_value_def<'a>(
|
|||
loc_can_pattern,
|
||||
loc_expr,
|
||||
Some(Loc::at(loc_ann.region, type_annotation)),
|
||||
DefKind::Let,
|
||||
)
|
||||
}
|
||||
Body(loc_can_pattern, loc_expr) => {
|
||||
|
@ -2421,6 +2447,20 @@ fn canonicalize_pending_value_def<'a>(
|
|||
loc_can_pattern,
|
||||
loc_expr,
|
||||
None,
|
||||
DefKind::Let,
|
||||
)
|
||||
}
|
||||
Stmt(loc_expr) => {
|
||||
let fx_var = var_store.fresh();
|
||||
canonicalize_pending_body(
|
||||
env,
|
||||
output,
|
||||
scope,
|
||||
var_store,
|
||||
Loc::at(loc_expr.region, Pattern::Underscore),
|
||||
loc_expr,
|
||||
None,
|
||||
DefKind::Stmt(fx_var),
|
||||
)
|
||||
}
|
||||
ImportParams {
|
||||
|
@ -2461,6 +2501,7 @@ fn canonicalize_pending_value_def<'a>(
|
|||
var_store.fresh(),
|
||||
None,
|
||||
SendMap::default(),
|
||||
DefKind::Let,
|
||||
);
|
||||
|
||||
DefOutput {
|
||||
|
@ -2530,6 +2571,7 @@ fn canonicalize_pending_value_def<'a>(
|
|||
var_store.fresh(),
|
||||
opt_loc_can_ann,
|
||||
SendMap::default(),
|
||||
DefKind::Let,
|
||||
);
|
||||
|
||||
DefOutput {
|
||||
|
@ -2568,6 +2610,7 @@ fn canonicalize_pending_body<'a>(
|
|||
loc_expr: &'a Loc<ast::Expr>,
|
||||
|
||||
opt_loc_annotation: Option<Loc<crate::annotation::Annotation>>,
|
||||
kind: DefKind,
|
||||
) -> DefOutput {
|
||||
let mut loc_value = &loc_expr.value;
|
||||
|
||||
|
@ -2686,6 +2729,7 @@ fn canonicalize_pending_body<'a>(
|
|||
expr_var,
|
||||
opt_loc_annotation,
|
||||
vars_by_symbol,
|
||||
kind,
|
||||
);
|
||||
|
||||
DefOutput {
|
||||
|
@ -3075,10 +3119,7 @@ fn to_pending_value_def<'a>(
|
|||
loc_pattern.region,
|
||||
);
|
||||
|
||||
PendingValue::Def(PendingValueDef::AnnotationOnly(
|
||||
loc_can_pattern,
|
||||
loc_ann,
|
||||
))
|
||||
PendingValue::Def(PendingValueDef::AnnotationOnly(loc_can_pattern, loc_ann))
|
||||
}
|
||||
Body(loc_pattern, loc_expr) => {
|
||||
// This takes care of checking for shadowing and adding idents to scope.
|
||||
|
@ -3184,15 +3225,17 @@ fn to_pending_value_def<'a>(
|
|||
// Generate a symbol for the module params def
|
||||
// We do this even if params weren't provided so that solve can report if they are missing
|
||||
let params_sym = scope.gen_unique_symbol();
|
||||
let params_region = module_import.params.map(|p| p.params.region).unwrap_or(region);
|
||||
let params_region = module_import
|
||||
.params
|
||||
.map(|p| p.params.region)
|
||||
.unwrap_or(region);
|
||||
let params_var = var_store.fresh();
|
||||
let params =
|
||||
PendingModuleImportParams {
|
||||
symbol: params_sym,
|
||||
variable: params_var,
|
||||
loc_pattern: Loc::at(params_region, Pattern::Identifier(params_sym)),
|
||||
opt_provided: module_import.params.map(|p| p.params.value),
|
||||
};
|
||||
let params = PendingModuleImportParams {
|
||||
symbol: params_sym,
|
||||
variable: params_var,
|
||||
loc_pattern: Loc::at(params_region, Pattern::Identifier(params_sym)),
|
||||
opt_provided: module_import.params.map(|p| p.params.value),
|
||||
};
|
||||
let provided_params = if module_import.params.is_some() {
|
||||
// Only add params to scope if they are provided
|
||||
Some((params_var, params_sym))
|
||||
|
@ -3221,8 +3264,12 @@ fn to_pending_value_def<'a>(
|
|||
.map(|kw| kw.item.items)
|
||||
.unwrap_or_default();
|
||||
|
||||
if exposed_names.is_empty() && !env.home.is_builtin() && module_id.is_automatically_imported() {
|
||||
env.problems.push(Problem::ExplicitBuiltinImport(module_id, region));
|
||||
if exposed_names.is_empty()
|
||||
&& !env.home.is_builtin()
|
||||
&& module_id.is_automatically_imported()
|
||||
{
|
||||
env.problems
|
||||
.push(Problem::ExplicitBuiltinImport(module_id, region));
|
||||
}
|
||||
|
||||
let exposed_ids = env
|
||||
|
@ -3242,7 +3289,9 @@ fn to_pending_value_def<'a>(
|
|||
let symbol = Symbol::new(module_id, ident_id);
|
||||
exposed_symbols.push((symbol, loc_name.region));
|
||||
|
||||
if let Err((_shadowed_symbol, existing_symbol_region)) = scope.import_symbol(ident, symbol, loc_name.region) {
|
||||
if let Err((_shadowed_symbol, existing_symbol_region)) =
|
||||
scope.import_symbol(ident, symbol, loc_name.region)
|
||||
{
|
||||
if symbol.is_automatically_imported() {
|
||||
env.problem(Problem::ExplicitBuiltinTypeImport(
|
||||
symbol,
|
||||
|
@ -3257,14 +3306,12 @@ fn to_pending_value_def<'a>(
|
|||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
env.problem(Problem::RuntimeError(RuntimeError::ValueNotExposed {
|
||||
module_name: module_name.clone(),
|
||||
ident,
|
||||
region: loc_name.region,
|
||||
exposed_values: exposed_ids.exposed_values(),
|
||||
}))
|
||||
}
|
||||
None => env.problem(Problem::RuntimeError(RuntimeError::ValueNotExposed {
|
||||
module_name: module_name.clone(),
|
||||
ident,
|
||||
region: loc_name.region,
|
||||
exposed_values: exposed_ids.exposed_values(),
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3279,12 +3326,12 @@ fn to_pending_value_def<'a>(
|
|||
let loc_name = ingested_file.name.item;
|
||||
|
||||
let symbol = match scope.introduce(loc_name.value.into(), loc_name.region) {
|
||||
Ok(symbol ) => symbol,
|
||||
Ok(symbol) => symbol,
|
||||
Err((original, shadow, _)) => {
|
||||
env.problem(Problem::Shadowing {
|
||||
original_region: original.region,
|
||||
shadow,
|
||||
kind: ShadowKind::Variable
|
||||
kind: ShadowKind::Variable,
|
||||
});
|
||||
|
||||
return PendingValue::InvalidIngestedFile;
|
||||
|
@ -3293,10 +3340,20 @@ fn to_pending_value_def<'a>(
|
|||
|
||||
let loc_pattern = Loc::at(loc_name.region, Pattern::Identifier(symbol));
|
||||
|
||||
PendingValue::Def(PendingValueDef::IngestedFile(loc_pattern, ingested_file.annotation.map(|ann| ann.annotation), ingested_file.path))
|
||||
PendingValue::Def(PendingValueDef::IngestedFile(
|
||||
loc_pattern,
|
||||
ingested_file.annotation.map(|ann| ann.annotation),
|
||||
ingested_file.path,
|
||||
))
|
||||
}
|
||||
StmtAfterExpr => PendingValue::StmtAfterExpr,
|
||||
Stmt(_) => internal_error!("a Stmt was not desugared correctly, should have been converted to a Body(...) in desguar"),
|
||||
Stmt(expr) => {
|
||||
if env.fx_mode == FxMode::Task {
|
||||
internal_error!("a Stmt was not desugared correctly, should have been converted to a Body(...) in desguar")
|
||||
}
|
||||
|
||||
PendingValue::Def(PendingValueDef::Stmt(expr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -203,13 +203,19 @@ fn desugar_value_def<'a>(
|
|||
StmtAfterExpr => internal_error!("unexpected StmtAfterExpr"),
|
||||
|
||||
Stmt(stmt_expr) => {
|
||||
if env.fx_mode == FxMode::PurityInference {
|
||||
// In purity inference mode, statements aren't fully desugared here
|
||||
// so we can provide better errors
|
||||
return Stmt(desugar_expr(env, scope, stmt_expr));
|
||||
}
|
||||
|
||||
// desugar `stmt_expr!` to
|
||||
// _ : {}
|
||||
// _ = stmt_expr!
|
||||
|
||||
let desugared_expr = desugar_expr(env, scope, stmt_expr);
|
||||
|
||||
if env.fx_mode == FxMode::Task && !is_expr_suffixed(&desugared_expr.value) {
|
||||
if !is_expr_suffixed(&desugared_expr.value) {
|
||||
env.problems.push(Problem::StmtAfterExpr(stmt_expr.region));
|
||||
|
||||
return ValueDef::StmtAfterExpr;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::def::Def;
|
||||
use crate::def::{Def, DefKind};
|
||||
use crate::expr::{AnnotatedMark, ClosureData, Expr, Recursive};
|
||||
use crate::pattern::Pattern;
|
||||
use crate::scope::Scope;
|
||||
|
@ -211,6 +211,7 @@ pub fn build_host_exposed_def(
|
|||
expr_var,
|
||||
pattern_vars,
|
||||
annotation: Some(def_annotation),
|
||||
kind: DefKind::Let,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::abilities::SpecializationId;
|
||||
use crate::annotation::{freshen_opaque_def, IntroducedVariables};
|
||||
use crate::builtins::builtin_defs_map;
|
||||
use crate::def::{can_defs_with_return, Annotation, Def};
|
||||
use crate::def::{can_defs_with_return, Annotation, Def, DefKind};
|
||||
use crate::env::Env;
|
||||
use crate::num::{
|
||||
finish_parsing_base, finish_parsing_float, finish_parsing_num, float_expr_from_result,
|
||||
|
@ -2288,6 +2288,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
|
|||
expr_var: def.expr_var,
|
||||
pattern_vars: def.pattern_vars,
|
||||
annotation: def.annotation,
|
||||
kind: def.kind,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2309,6 +2310,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
|
|||
expr_var: def.expr_var,
|
||||
pattern_vars: def.pattern_vars,
|
||||
annotation: def.annotation,
|
||||
kind: def.kind,
|
||||
};
|
||||
|
||||
let loc_expr = Loc {
|
||||
|
@ -2498,6 +2500,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
|
|||
expr_var,
|
||||
pattern_vars,
|
||||
annotation: None,
|
||||
kind: DefKind::Let,
|
||||
};
|
||||
|
||||
loc_answer = Loc {
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::path::Path;
|
|||
|
||||
use crate::abilities::{AbilitiesStore, ImplKey, PendingAbilitiesStore, ResolvedImpl};
|
||||
use crate::annotation::{canonicalize_annotation, AnnotationFor};
|
||||
use crate::def::{canonicalize_defs, report_unused_imports, Def};
|
||||
use crate::def::{canonicalize_defs, report_unused_imports, Def, DefKind};
|
||||
use crate::desugar::desugar_record_destructures;
|
||||
use crate::env::{Env, FxMode};
|
||||
use crate::expr::{
|
||||
|
@ -657,6 +657,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
expr_var: var_store.fresh(),
|
||||
pattern_vars,
|
||||
annotation: None,
|
||||
kind: DefKind::Let,
|
||||
};
|
||||
|
||||
declarations.push_def(def);
|
||||
|
|
|
@ -10,7 +10,7 @@ use roc_can::annotation::IntroducedVariables;
|
|||
use roc_can::constraint::{
|
||||
Constraint, Constraints, ExpectedTypeIndex, Generalizable, OpportunisticResolve, TypeOrVar,
|
||||
};
|
||||
use roc_can::def::Def;
|
||||
use roc_can::def::{Def, DefKind};
|
||||
use roc_can::exhaustive::{sketch_pattern_to_rows, sketch_when_branches, ExhaustiveContext};
|
||||
use roc_can::expected::Expected::{self, *};
|
||||
use roc_can::expected::PExpected;
|
||||
|
@ -1469,7 +1469,12 @@ pub fn constrain_expr(
|
|||
);
|
||||
|
||||
while let Some(def) = stack.pop() {
|
||||
body_con = constrain_def(types, constraints, env, def, body_con)
|
||||
body_con = match def.kind {
|
||||
DefKind::Let => constrain_let_def(types, constraints, env, def, body_con),
|
||||
DefKind::Stmt(fx_var) => {
|
||||
constrain_stmt_def(types, constraints, env, def, body_con, fx_var)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
body_con
|
||||
|
@ -3423,7 +3428,7 @@ fn attach_resolution_constraints(
|
|||
constraints.and_constraint([constraint, resolution_constrs])
|
||||
}
|
||||
|
||||
fn constrain_def(
|
||||
fn constrain_let_def(
|
||||
types: &mut Types,
|
||||
constraints: &mut Constraints,
|
||||
env: &mut Env,
|
||||
|
@ -3468,6 +3473,46 @@ fn constrain_def(
|
|||
}
|
||||
}
|
||||
|
||||
fn constrain_stmt_def(
|
||||
types: &mut Types,
|
||||
constraints: &mut Constraints,
|
||||
env: &mut Env,
|
||||
def: &Def,
|
||||
body_con: Constraint,
|
||||
fx_var: Variable,
|
||||
) -> Constraint {
|
||||
// [purity-inference] TODO: Require fx is effectful
|
||||
|
||||
// Statement expressions must return an empty record
|
||||
let empty_record_index = constraints.push_type(types, Types::EMPTY_RECORD);
|
||||
let expected = constraints.push_expected_type(ForReason(
|
||||
Reason::Stmt,
|
||||
empty_record_index,
|
||||
def.loc_expr.region,
|
||||
));
|
||||
|
||||
let expr_con = constrain_expr(
|
||||
types,
|
||||
constraints,
|
||||
env,
|
||||
def.loc_expr.region,
|
||||
&def.loc_expr.value,
|
||||
expected,
|
||||
);
|
||||
let expr_con = attach_resolution_constraints(constraints, env, expr_con);
|
||||
|
||||
let generalizable = Generalizable(is_generalizable_expr(&def.loc_expr.value));
|
||||
|
||||
constraints.let_constraint(
|
||||
std::iter::empty(),
|
||||
std::iter::empty(),
|
||||
std::iter::empty(),
|
||||
expr_con,
|
||||
body_con,
|
||||
generalizable,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a let-constraint for a non-recursive def.
|
||||
/// Recursive defs should always use `constrain_recursive_defs`.
|
||||
pub(crate) fn constrain_def_make_constraint(
|
||||
|
|
|
@ -4,6 +4,7 @@ use std::iter::once;
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use roc_can::abilities::SpecializationLambdaSets;
|
||||
use roc_can::def::DefKind;
|
||||
use roc_can::expr::Expr;
|
||||
use roc_can::pattern::Pattern;
|
||||
use roc_can::{def::Def, module::ExposedByModule};
|
||||
|
@ -90,6 +91,7 @@ fn build_derived_body(
|
|||
expr_var: body_type,
|
||||
pattern_vars: once((derived_symbol, body_type)).collect(),
|
||||
annotation: None,
|
||||
kind: DefKind::Let,
|
||||
};
|
||||
|
||||
(def, specialization_lambda_sets)
|
||||
|
|
|
@ -184,6 +184,7 @@ fn remove_for_reason(
|
|||
| Reason::ImportParams(_)
|
||||
| Reason::CallInFunction(_)
|
||||
| Reason::CallInTopLevelDef
|
||||
| Reason::Stmt
|
||||
| Reason::FunctionOutput => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2620,6 +2620,7 @@ fn from_can_let<'a>(
|
|||
expr_var: def.expr_var,
|
||||
pattern_vars: std::iter::once((anon_name, def.expr_var)).collect(),
|
||||
annotation: None,
|
||||
kind: def.kind,
|
||||
});
|
||||
|
||||
// f = #lam
|
||||
|
@ -2629,6 +2630,7 @@ fn from_can_let<'a>(
|
|||
expr_var: def.expr_var,
|
||||
pattern_vars: def.pattern_vars,
|
||||
annotation: def.annotation,
|
||||
kind: def.kind,
|
||||
});
|
||||
|
||||
let new_inner = LetNonRec(new_def, cont);
|
||||
|
@ -2648,6 +2650,7 @@ fn from_can_let<'a>(
|
|||
pattern_vars: def.pattern_vars,
|
||||
annotation: def.annotation,
|
||||
expr_var: def.expr_var,
|
||||
kind: def.kind,
|
||||
};
|
||||
|
||||
let new_inner = LetNonRec(Box::new(new_def), cont);
|
||||
|
@ -2687,6 +2690,7 @@ fn from_can_let<'a>(
|
|||
pattern_vars: def.pattern_vars,
|
||||
annotation: def.annotation,
|
||||
expr_var: def.expr_var,
|
||||
kind: def.kind,
|
||||
};
|
||||
|
||||
let new_inner = LetNonRec(Box::new(new_def), cont);
|
||||
|
@ -7292,6 +7296,7 @@ fn to_opt_branches<'a>(
|
|||
roc_can::pattern::Pattern::Identifier(symbol),
|
||||
),
|
||||
pattern_vars: std::iter::once((symbol, variable)).collect(),
|
||||
kind: roc_can::def::DefKind::Let,
|
||||
};
|
||||
let new_expr =
|
||||
roc_can::expr::Expr::LetNonRec(Box::new(def), Box::new(loc_expr));
|
||||
|
|
|
@ -3448,6 +3448,7 @@ pub enum Reason {
|
|||
foreign_symbol: ForeignSymbol,
|
||||
arg_index: HumanIndex,
|
||||
},
|
||||
Stmt,
|
||||
CallInFunction(Option<Region>),
|
||||
CallInTopLevelDef,
|
||||
FloatLiteral,
|
||||
|
|
|
@ -1681,6 +1681,7 @@ fn to_expr_report<'b>(
|
|||
}
|
||||
Reason::CallInFunction(_) => todo!("[purity-inference] CallInFunction"),
|
||||
Reason::CallInTopLevelDef => todo!("[purity-inference] CallInTopLevelDef"),
|
||||
Reason::Stmt => todo!("[purity-inference] Stmt"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue