Add constraint generation for opaque types

This commit is contained in:
ayazhafiz 2022-02-23 00:42:17 -05:00
parent d3acf34415
commit 86aa0df661
13 changed files with 499 additions and 172 deletions

View file

@ -12,13 +12,12 @@ use roc_can::expr::Expr::{self, *};
use roc_can::expr::{ClosureData, Field, WhenBranch};
use roc_can::pattern::Pattern;
use roc_collections::all::{ImMap, Index, MutSet, SendMap};
use roc_error_macros::todo_opaques;
use roc_module::ident::{Lowercase, TagName};
use roc_module::symbol::{ModuleId, Symbol};
use roc_region::all::{Loc, Region};
use roc_types::subs::Variable;
use roc_types::types::Type::{self, *};
use roc_types::types::{AnnotationSource, Category, PReason, Reason, RecordField};
use roc_types::types::{AliasKind, AnnotationSource, Category, PReason, Reason, RecordField};
/// This is for constraining Defs
#[derive(Default, Debug)]
@ -917,7 +916,71 @@ pub fn constrain_expr(
exists(vars, And(arg_cons))
}
OpaqueRef { .. } => todo_opaques!(),
OpaqueRef {
opaque_var,
name,
argument,
specialized_def_type,
type_arguments,
lambda_set_variables,
} => {
let (arg_var, arg_loc_expr) = &**argument;
let arg_type = Type::Variable(*arg_var);
let opaque_type = Type::Alias {
symbol: *name,
type_arguments: type_arguments.clone(),
lambda_set_variables: lambda_set_variables.clone(),
actual: Box::new(arg_type.clone()),
kind: AliasKind::Opaque,
};
// Constrain the argument
let arg_con = constrain_expr(
env,
arg_loc_expr.region,
&arg_loc_expr.value,
Expected::NoExpectation(arg_type.clone()),
);
// Link the entire wrapped opaque type (with the now-constrained argument) to the
// expected type
let opaque_con = Eq(
opaque_type,
expected.clone(),
Category::OpaqueWrap(*name),
region,
);
// Link the entire wrapped opaque type (with the now-constrained argument) to the type
// variables of the opaque type
// TODO: better expectation here
let link_type_variables_con = Eq(
(**specialized_def_type).clone(),
Expected::NoExpectation(arg_type),
Category::OpaqueWrap(*name),
arg_loc_expr.region,
);
// Store the entire wrapped opaque type in `opaque_var`
let storage_con = Eq(
Type::Variable(*opaque_var),
expected,
Category::Storage(std::file!(), std::line!()),
region,
);
exists(
// TODO: may need to extend with vars from `type_arguments` and `lambda_set_variables` here!
vec![*arg_var, *opaque_var],
And(vec![
arg_con,
opaque_con,
link_type_variables_con,
storage_con,
]),
)
}
RunLowLevel { args, ret_var, op } => {
// This is a modified version of what we do for function calls.