Fix type-inferrer on arrays
This commit is contained in:
parent
f9f9360efc
commit
a511331be2
@ -578,19 +578,6 @@ impl mir::Expression {
|
|||||||
lit.as_type(),
|
lit.as_type(),
|
||||||
)),
|
)),
|
||||||
mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => {
|
mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => {
|
||||||
lhs_exp
|
|
||||||
.return_type()
|
|
||||||
.expect("No ret type in lhs?")
|
|
||||||
.1
|
|
||||||
.known()
|
|
||||||
.expect("lhs ret type is unknown");
|
|
||||||
rhs_exp
|
|
||||||
.return_type()
|
|
||||||
.expect("No ret type in rhs?")
|
|
||||||
.1
|
|
||||||
.known()
|
|
||||||
.expect("rhs ret type is unknown");
|
|
||||||
|
|
||||||
let lhs = lhs_exp
|
let lhs = lhs_exp
|
||||||
.codegen(scope, state)
|
.codegen(scope, state)
|
||||||
.expect("lhs has no return value")
|
.expect("lhs has no return value")
|
||||||
@ -741,7 +728,7 @@ impl mir::Expression {
|
|||||||
mir::ExprKind::Accessed(expression, type_kind, field) => {
|
mir::ExprKind::Accessed(expression, type_kind, field) => {
|
||||||
let struct_val = expression.codegen(scope, &mut state.load(true)).unwrap();
|
let struct_val = expression.codegen(scope, &mut state.load(true)).unwrap();
|
||||||
|
|
||||||
let TypeKind::CustomType(name) = struct_val.1.deref_borrow() else {
|
let TypeKind::CustomType(name) = &struct_val.1 else {
|
||||||
panic!("tried accessing non-custom-type");
|
panic!("tried accessing non-custom-type");
|
||||||
};
|
};
|
||||||
let TypeDefinitionKind::Struct(struct_ty) =
|
let TypeDefinitionKind::Struct(struct_ty) =
|
||||||
@ -969,9 +956,6 @@ impl TypeKind {
|
|||||||
TypeDefinitionKind::Struct(_) => Type::Ptr(Box::new(custom_t)),
|
TypeDefinitionKind::Struct(_) => Type::Ptr(Box::new(custom_t)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeKind::Borrow(type_kind) => {
|
|
||||||
Type::Ptr(Box::new(type_kind.get_type(type_vals, typedefs)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,6 @@ impl TypeKind {
|
|||||||
TypeKind::Void => 0,
|
TypeKind::Void => 0,
|
||||||
TypeKind::StringPtr => 32,
|
TypeKind::StringPtr => 32,
|
||||||
TypeKind::Array(type_kind, len) => 32,
|
TypeKind::Array(type_kind, len) => 32,
|
||||||
TypeKind::Borrow(_) => todo!(),
|
|
||||||
TypeKind::CustomType(_) => 32,
|
TypeKind::CustomType(_) => 32,
|
||||||
TypeKind::Vague(_) => panic!("Tried to sizeof a vague type!"),
|
TypeKind::Vague(_) => panic!("Tried to sizeof a vague type!"),
|
||||||
}
|
}
|
||||||
@ -69,7 +68,6 @@ impl TypeKind {
|
|||||||
TypeKind::Void => DwarfEncoding::Address,
|
TypeKind::Void => DwarfEncoding::Address,
|
||||||
TypeKind::StringPtr => DwarfEncoding::Address,
|
TypeKind::StringPtr => DwarfEncoding::Address,
|
||||||
TypeKind::Array(_, _) => DwarfEncoding::Address,
|
TypeKind::Array(_, _) => DwarfEncoding::Address,
|
||||||
TypeKind::Borrow(_) => DwarfEncoding::Address,
|
|
||||||
TypeKind::CustomType(_) => DwarfEncoding::Address,
|
TypeKind::CustomType(_) => DwarfEncoding::Address,
|
||||||
TypeKind::Vague(_) => panic!("tried fetching debug-type for vague type!"),
|
TypeKind::Vague(_) => panic!("tried fetching debug-type for vague type!"),
|
||||||
},
|
},
|
||||||
@ -104,7 +102,7 @@ impl Block {
|
|||||||
let mut early_return = None;
|
let mut early_return = None;
|
||||||
|
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
let ret = statement.return_type();
|
let ret = statement.return_type(&Default::default());
|
||||||
if let Ok((ReturnKind::Hard, _)) = ret {
|
if let Ok((ReturnKind::Hard, _)) = ret {
|
||||||
early_return = Some(statement);
|
early_return = Some(statement);
|
||||||
}
|
}
|
||||||
@ -128,11 +126,11 @@ impl Block {
|
|||||||
.unwrap_or(self.meta)
|
.unwrap_or(self.meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
pub fn return_type(&self, refs: &TypeRefs) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||||
let mut early_return = None;
|
let mut early_return = None;
|
||||||
|
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
let ret = statement.return_type();
|
let ret = statement.return_type(refs);
|
||||||
if let Ok((ReturnKind::Hard, _)) = ret {
|
if let Ok((ReturnKind::Hard, _)) = ret {
|
||||||
early_return = early_return.or(ret.ok());
|
early_return = early_return.or(ret.ok());
|
||||||
}
|
}
|
||||||
@ -145,7 +143,7 @@ impl Block {
|
|||||||
self.return_expression
|
self.return_expression
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or(ReturnTypeOther::NoBlockReturn(self.meta))
|
.ok_or(ReturnTypeOther::NoBlockReturn(self.meta))
|
||||||
.and_then(|(kind, stmt)| Ok((*kind, stmt.return_type()?.1)))
|
.and_then(|(kind, stmt)| Ok((*kind, stmt.return_type(refs)?.1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn backing_var(&self) -> Option<&NamedVariableRef> {
|
pub fn backing_var(&self) -> Option<&NamedVariableRef> {
|
||||||
@ -163,16 +161,19 @@ impl Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Statement {
|
impl Statement {
|
||||||
pub fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
pub fn return_type(&self, refs: &TypeRefs) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||||
use StmtKind::*;
|
use StmtKind::*;
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
Let(var, _, expr) => if_hard(
|
Let(var, _, expr) => if_hard(
|
||||||
expr.return_type()?,
|
expr.return_type(refs)?,
|
||||||
Err(ReturnTypeOther::Let(var.2 + expr.1)),
|
Err(ReturnTypeOther::Let(var.2 + expr.1)),
|
||||||
),
|
),
|
||||||
Set(lhs, rhs) => if_hard(rhs.return_type()?, Err(ReturnTypeOther::Set(lhs.1 + rhs.1))),
|
Set(lhs, rhs) => if_hard(
|
||||||
|
rhs.return_type(refs)?,
|
||||||
|
Err(ReturnTypeOther::Set(lhs.1 + rhs.1)),
|
||||||
|
),
|
||||||
Import(_) => todo!(),
|
Import(_) => todo!(),
|
||||||
Expression(expression) => expression.return_type(),
|
Expression(expression) => expression.return_type(refs),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,24 +188,25 @@ impl Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
pub fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
pub fn return_type(&self, refs: &TypeRefs) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||||
use ExprKind::*;
|
use ExprKind::*;
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
Literal(lit) => Ok((ReturnKind::Soft, lit.as_type())),
|
Literal(lit) => Ok((ReturnKind::Soft, lit.as_type())),
|
||||||
Variable(var) => var.return_type(),
|
Variable(var) => var.return_type(),
|
||||||
BinOp(_, then_e, else_e) => {
|
BinOp(_, then_e, else_e) => {
|
||||||
let then_r = then_e.return_type()?;
|
let then_r = then_e.return_type(refs)?;
|
||||||
let else_r = else_e.return_type()?;
|
let else_r = else_e.return_type(refs)?;
|
||||||
|
|
||||||
Ok(pick_return(then_r, else_r))
|
Ok(pick_return(then_r, else_r))
|
||||||
}
|
}
|
||||||
Block(block) => block.return_type(),
|
Block(block) => block.return_type(refs),
|
||||||
FunctionCall(fcall) => fcall.return_type(),
|
FunctionCall(fcall) => fcall.return_type(),
|
||||||
If(expr) => expr.return_type(),
|
If(expr) => expr.return_type(refs),
|
||||||
Indexed(expression, _, _) => {
|
Indexed(expression, _, _) => {
|
||||||
let expr_type = expression.return_type()?;
|
let expr_type = expression.return_type(refs)?;
|
||||||
if let (_, TypeKind::Array(elem_ty, _)) = expr_type {
|
dbg!(&expr_type);
|
||||||
Ok((ReturnKind::Soft, TypeKind::Borrow(Box::new(*elem_ty))))
|
if let TypeKind::Array(elem_ty, _) = expr_type.1.resolve_weak(refs) {
|
||||||
|
Ok((ReturnKind::Soft, *elem_ty))
|
||||||
} else {
|
} else {
|
||||||
Err(ReturnTypeOther::IndexingNonArray(expression.1))
|
Err(ReturnTypeOther::IndexingNonArray(expression.1))
|
||||||
}
|
}
|
||||||
@ -213,17 +215,14 @@ impl Expression {
|
|||||||
let first = expressions
|
let first = expressions
|
||||||
.iter()
|
.iter()
|
||||||
.next()
|
.next()
|
||||||
.map(|e| e.return_type())
|
.map(|e| e.return_type(refs))
|
||||||
.unwrap_or(Ok((ReturnKind::Soft, TypeKind::Void)))?;
|
.unwrap_or(Ok((ReturnKind::Soft, TypeKind::Void)))?;
|
||||||
Ok((
|
Ok((
|
||||||
ReturnKind::Soft,
|
ReturnKind::Soft,
|
||||||
TypeKind::Array(Box::new(first.1), expressions.len() as u64),
|
TypeKind::Array(Box::new(first.1), expressions.len() as u64),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Accessed(_, type_kind, _) => Ok((
|
Accessed(_, type_kind, _) => Ok((ReturnKind::Soft, type_kind.clone())),
|
||||||
ReturnKind::Soft,
|
|
||||||
TypeKind::Borrow(Box::new(type_kind.clone())),
|
|
||||||
)),
|
|
||||||
Struct(name, _) => Ok((ReturnKind::Soft, TypeKind::CustomType(name.clone()))),
|
Struct(name, _) => Ok((ReturnKind::Soft, TypeKind::CustomType(name.clone()))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -245,10 +244,10 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl IfExpression {
|
impl IfExpression {
|
||||||
pub fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
pub fn return_type(&self, refs: &TypeRefs) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||||
let then_r = self.1.return_type()?;
|
let then_r = self.1.return_type(refs)?;
|
||||||
if let Some(else_b) = &self.2 {
|
if let Some(else_b) = &self.2 {
|
||||||
let else_r = else_b.return_type()?;
|
let else_r = else_b.return_type(refs)?;
|
||||||
|
|
||||||
let kind = if then_r.0 == ReturnKind::Hard && else_r.0 == ReturnKind::Hard {
|
let kind = if then_r.0 == ReturnKind::Hard && else_r.0 == ReturnKind::Hard {
|
||||||
ReturnKind::Hard
|
ReturnKind::Hard
|
||||||
@ -315,21 +314,18 @@ impl TypeKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_ref(&self, refs: &TypeRefs) -> TypeKind {
|
pub fn resolve_weak(&self, refs: &TypeRefs) -> TypeKind {
|
||||||
let resolved = match self {
|
match self {
|
||||||
TypeKind::Vague(Vague::TypeRef(idx)) => refs.retrieve_type(*idx).unwrap(),
|
TypeKind::Vague(Vague::TypeRef(idx)) => refs.retrieve_type(*idx).unwrap(),
|
||||||
_ => self.clone(),
|
_ => self.clone(),
|
||||||
};
|
|
||||||
match resolved {
|
|
||||||
TypeKind::Array(t, len) => TypeKind::Array(Box::new(t.resolve_ref(refs)), len),
|
|
||||||
_ => resolved,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deref_borrow(&self) -> TypeKind {
|
pub fn resolve_ref(&self, refs: &TypeRefs) -> TypeKind {
|
||||||
match self {
|
let resolved = self.resolve_weak(refs);
|
||||||
TypeKind::Borrow(type_kind) => *type_kind.clone(),
|
match resolved {
|
||||||
_ => self.clone(),
|
TypeKind::Array(t, len) => TypeKind::Array(Box::new(t.resolve_ref(refs)), len),
|
||||||
|
_ => resolved,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,10 +95,10 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
modules.insert(module.name.clone(), Rc::new(RefCell::new((module, tokens))));
|
modules.insert(module.name.clone(), Rc::new(RefCell::new((module, tokens))));
|
||||||
}
|
}
|
||||||
|
|
||||||
modules.insert(
|
// modules.insert(
|
||||||
"std".to_owned(),
|
// "std".to_owned(),
|
||||||
Rc::new(RefCell::new(compile_std(&mut self.module_map))),
|
// Rc::new(RefCell::new(compile_std(&mut self.module_map))),
|
||||||
);
|
// );
|
||||||
|
|
||||||
let mut modules_to_process: Vec<Rc<RefCell<(Module, Vec<FullToken>)>>> =
|
let mut modules_to_process: Vec<Rc<RefCell<(Module, Vec<FullToken>)>>> =
|
||||||
modules.values().cloned().collect();
|
modules.values().cloned().collect();
|
||||||
|
@ -107,8 +107,6 @@ pub enum TypeKind {
|
|||||||
StringPtr,
|
StringPtr,
|
||||||
#[error("[{0}; {1}]")]
|
#[error("[{0}; {1}]")]
|
||||||
Array(Box<TypeKind>, u64),
|
Array(Box<TypeKind>, u64),
|
||||||
#[error("Borrow({0})")]
|
|
||||||
Borrow(Box<TypeKind>),
|
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
CustomType(String),
|
CustomType(String),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
@ -299,7 +299,7 @@ impl Block {
|
|||||||
StmtKind::Expression(expression) => {
|
StmtKind::Expression(expression) => {
|
||||||
let res = expression.typecheck(&mut state, &typerefs, None);
|
let res = expression.typecheck(&mut state, &typerefs, None);
|
||||||
state.or_else(res, TypeKind::Void, expression.1);
|
state.or_else(res, TypeKind::Void, expression.1);
|
||||||
if let Ok((kind, _)) = expression.return_type() {
|
if let Ok((kind, _)) = expression.return_type(typerefs) {
|
||||||
Some((kind, expression))
|
Some((kind, expression))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -78,17 +78,17 @@ impl Block {
|
|||||||
fn infer_types<'s>(
|
fn infer_types<'s>(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut TypeInferencePassState,
|
state: &mut TypeInferencePassState,
|
||||||
outer_hints: &'s ScopeTypeRefs,
|
outer_refs: &'s ScopeTypeRefs,
|
||||||
) -> Result<(ReturnKind, TypeRef<'s>), ErrorKind> {
|
) -> Result<(ReturnKind, TypeRef<'s>), ErrorKind> {
|
||||||
let mut state = state.inner();
|
let mut state = state.inner();
|
||||||
let inner_hints = outer_hints.inner();
|
let inner_refs = outer_refs.inner();
|
||||||
|
|
||||||
for statement in &mut self.statements {
|
for statement in &mut self.statements {
|
||||||
match &mut statement.0 {
|
match &mut statement.0 {
|
||||||
StmtKind::Let(var, mutable, expr) => {
|
StmtKind::Let(var, mutable, expr) => {
|
||||||
// Get the TypeRef for this variable declaration
|
// Get the TypeRef for this variable declaration
|
||||||
let mut var_ref =
|
let mut var_ref =
|
||||||
state.ok(inner_hints.new_var(var.1.clone(), *mutable, &var.0), var.2);
|
state.ok(inner_refs.new_var(var.1.clone(), *mutable, &var.0), var.2);
|
||||||
|
|
||||||
// If ok, update the MIR type to this TypeRef
|
// If ok, update the MIR type to this TypeRef
|
||||||
if let Some(var_ref) = &var_ref {
|
if let Some(var_ref) = &var_ref {
|
||||||
@ -96,7 +96,7 @@ impl Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Infer hints for the expression itself
|
// Infer hints for the expression itself
|
||||||
let inferred = expr.infer_types(&mut state, &inner_hints);
|
let inferred = expr.infer_types(&mut state, &inner_refs);
|
||||||
let mut expr_ty_ref = state.ok(inferred, expr.1);
|
let mut expr_ty_ref = state.ok(inferred, expr.1);
|
||||||
|
|
||||||
// Try to narrow the variable type declaration with the
|
// Try to narrow the variable type declaration with the
|
||||||
@ -105,16 +105,15 @@ impl Block {
|
|||||||
(var_ref.as_mut(), expr_ty_ref.as_mut())
|
(var_ref.as_mut(), expr_ty_ref.as_mut())
|
||||||
{
|
{
|
||||||
var_ref.narrow(&expr_ty_ref);
|
var_ref.narrow(&expr_ty_ref);
|
||||||
dbg!(var_ref);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StmtKind::Set(lhs, rhs) => {
|
StmtKind::Set(lhs, rhs) => {
|
||||||
// Infer hints for the expression itself
|
// Infer hints for the expression itself
|
||||||
let lhs_infer = lhs.infer_types(&mut state, &inner_hints);
|
let lhs_infer = lhs.infer_types(&mut state, &inner_refs);
|
||||||
let lhs_ref = state.ok(lhs_infer, rhs.1);
|
let lhs_ref = state.ok(lhs_infer, rhs.1);
|
||||||
|
|
||||||
// Infer hints for the expression itself
|
// Infer hints for the expression itself
|
||||||
let rhs_infer = rhs.infer_types(&mut state, &inner_hints);
|
let rhs_infer = rhs.infer_types(&mut state, &inner_refs);
|
||||||
let rhs_ref = state.ok(rhs_infer, rhs.1);
|
let rhs_ref = state.ok(rhs_infer, rhs.1);
|
||||||
|
|
||||||
// Try to narrow the lhs with rhs
|
// Try to narrow the lhs with rhs
|
||||||
@ -124,7 +123,7 @@ impl Block {
|
|||||||
}
|
}
|
||||||
StmtKind::Import(_) => todo!(),
|
StmtKind::Import(_) => todo!(),
|
||||||
StmtKind::Expression(expr) => {
|
StmtKind::Expression(expr) => {
|
||||||
let expr_res = expr.infer_types(&mut state, &inner_hints);
|
let expr_res = expr.infer_types(&mut state, &inner_refs);
|
||||||
state.ok(expr_res, expr.1);
|
state.ok(expr_res, expr.1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -132,18 +131,22 @@ impl Block {
|
|||||||
|
|
||||||
// If there is a return expression, infer it's type
|
// If there is a return expression, infer it's type
|
||||||
if let Some(ret_expr) = &mut self.return_expression {
|
if let Some(ret_expr) = &mut self.return_expression {
|
||||||
let ret_res = ret_expr.1.infer_types(&mut state, &inner_hints);
|
let ret_res = ret_expr.1.infer_types(&mut state, &inner_refs);
|
||||||
state.ok(ret_res, ret_expr.1 .1);
|
state.ok(ret_res, ret_expr.1 .1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the declared return type
|
// Fetch the declared return type
|
||||||
let (kind, ty) = self.return_type().ok().unwrap_or((ReturnKind::Soft, Void));
|
let (kind, ty) = self
|
||||||
let mut ret_type_ref = outer_hints.from_type(&ty).unwrap();
|
.return_type(inner_refs.types)
|
||||||
|
.ok()
|
||||||
|
.unwrap_or((ReturnKind::Soft, Void));
|
||||||
|
let mut ret_type_ref = outer_refs.from_type(&ty).unwrap();
|
||||||
|
dbg!(&self.return_type(inner_refs.types));
|
||||||
|
|
||||||
// Narow return type to declared type if hard return
|
// Narow return type to declared type if hard return
|
||||||
if kind == ReturnKind::Hard {
|
if kind == ReturnKind::Hard {
|
||||||
if let Some(hint) = &state.scope.return_type_hint {
|
if let Some(hint) = &state.scope.return_type_hint {
|
||||||
ret_type_ref.narrow(&mut outer_hints.from_type(&hint).unwrap());
|
ret_type_ref.narrow(&mut outer_refs.from_type(&hint).unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,10 +347,8 @@ impl Expression {
|
|||||||
for field in fields {
|
for field in fields {
|
||||||
if let Some(expected_field_ty) = expected_struct_ty.get_field_ty(&field.0) {
|
if let Some(expected_field_ty) = expected_struct_ty.get_field_ty(&field.0) {
|
||||||
let field_ty = field.1.infer_types(state, type_refs);
|
let field_ty = field.1.infer_types(state, type_refs);
|
||||||
dbg!(&field_ty, expected_field_ty);
|
|
||||||
if let Some(mut field_ty) = state.ok(field_ty, field.1 .1) {
|
if let Some(mut field_ty) = state.ok(field_ty, field.1 .1) {
|
||||||
field_ty.narrow(&type_refs.from_type(&expected_field_ty).unwrap());
|
field_ty.narrow(&type_refs.from_type(&expected_field_ty).unwrap());
|
||||||
dbg!(&field_ty);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
|
@ -120,7 +120,7 @@ impl TypeRefs {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ScopeTypeRefs<'outer> {
|
pub struct ScopeTypeRefs<'outer> {
|
||||||
types: &'outer TypeRefs,
|
pub types: &'outer TypeRefs,
|
||||||
outer: Option<&'outer ScopeTypeRefs<'outer>>,
|
outer: Option<&'outer ScopeTypeRefs<'outer>>,
|
||||||
/// Mapping of what types variables point to
|
/// Mapping of what types variables point to
|
||||||
variables: RefCell<HashMap<String, (bool, TypeIdRef)>>,
|
variables: RefCell<HashMap<String, (bool, TypeIdRef)>>,
|
||||||
|
Loading…
Reference in New Issue
Block a user