From da861ebad00a6f336d7fc7cbc99bf8703cd4b567 Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Sun, 11 Aug 2019 14:20:06 +0200 Subject: [PATCH] perf(check): Only add implicit fields if the binding is implicit When encountering a binding we no longer recurse through the entire record but instead only do it as long as we are in a implicit binding already. Thus adding `Applicative` also adds its `Functor` field since `Applicative` is implicit. However, for a normal record such as from `let int = import! std.int` we no longer recurse and add all the implicit instances in `std.int`, instead a `let int @ { ? }` is required. BREAKING CHANGE --- base/src/resolve.rs | 35 ++++++++++++++++++------- check/src/implicits.rs | 58 +++++++++++++++++++++++++++++------------- tests/vm.rs | 24 ----------------- 3 files changed, 66 insertions(+), 51 deletions(-) diff --git a/base/src/resolve.rs b/base/src/resolve.rs index 4585bd491f..8655e2a37d 100644 --- a/base/src/resolve.rs +++ b/base/src/resolve.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; use crate::{ fnv::FnvMap, symbol::Symbol, - types::{AliasRef, Type, TypeContext, TypeEnv, TypeExt}, + types::{AliasData, AliasRef, Type, TypeContext, TypeEnv, TypeExt}, }; quick_error! { @@ -106,7 +106,7 @@ impl AliasRemover { T: TypeExt + ::std::fmt::Display, { loop { - typ = match self.remove_alias_to_concrete(env, interner, &typ)? { + typ = match self.remove_alias_to_concrete(env, interner, &typ, |_| true)? { Some((typ, args)) => match *typ { Type::Builtin(..) | Type::Function(..) @@ -134,16 +134,29 @@ impl AliasRemover { } pub fn remove_aliases( + &mut self, + env: &dyn TypeEnv, + interner: &mut impl TypeContext, + typ: T, + ) -> Result + where + T: TypeExt + ::std::fmt::Display, + { + self.remove_aliases_predicate(env, interner, typ, |_| true) + } + + pub fn remove_aliases_predicate( &mut self, env: &dyn TypeEnv, interner: &mut impl TypeContext, mut typ: T, + mut predicate: impl FnMut(&AliasData) -> bool, ) -> Result where T: TypeExt + ::std::fmt::Display, { loop { - typ = match self.remove_alias(env, interner, &typ)? { + typ = match self.remove_alias(env, interner, &typ, &mut predicate)? { Some(typ) => typ, None => return Ok(typ), }; @@ -155,19 +168,20 @@ impl AliasRemover { env: &dyn TypeEnv, interner: &mut impl TypeContext, typ: &T, + predicate: impl FnOnce(&AliasData) -> bool, ) -> Result, Error> where T: TypeExt + ::std::fmt::Display, { - Ok(self.remove_alias_to_concrete(env, interner, typ)?.map( - |(non_replaced_type, unapplied_args)| { + Ok(self + .remove_alias_to_concrete(env, interner, typ, predicate)? + .map(|(non_replaced_type, unapplied_args)| { let non_replaced_type = non_replaced_type .replace_generics(interner, &mut self.named_variables) .unwrap_or_else(|| non_replaced_type.clone()); interner.app(non_replaced_type, unapplied_args.iter().cloned().collect()) - }, - )) + })) } pub fn remove_alias_to_concrete<'a>( @@ -175,13 +189,16 @@ impl AliasRemover { env: &'a dyn TypeEnv, interner: &mut impl TypeContext, typ: &'a T, + predicate: impl FnOnce(&AliasData) -> bool, ) -> Result)>, Error> where T: TypeExt + ::std::fmt::Display, { match peek_alias(env, &typ)? { - Some(alias) => self.remove_alias_to_concrete_inner(interner, typ, alias), - None => Ok(None), + Some(alias) if predicate(alias) => { + self.remove_alias_to_concrete_inner(interner, typ, alias) + } + _ => Ok(None), } } diff --git a/check/src/implicits.rs b/check/src/implicits.rs index 8278aa1949..c1b6b0ea2a 100644 --- a/check/src/implicits.rs +++ b/check/src/implicits.rs @@ -776,7 +776,17 @@ impl<'a> ImplicitResolver<'a> { } pub fn on_stack_var(&mut self, subs: &Substitution, id: &Symbol, typ: &RcType) { - self.add_implicits_of_record(subs, id, typ); + self.alias_resolver.clear(); + + self.path.clear(); + self.path.push(TypedIdent { + name: id.clone(), + typ: typ.clone(), + }); + + let meta = self.metadata.get(id).cloned(); + + self.add_implicits_of_ident(subs, typ, meta.as_ref().map(|m| &**m), &mut Vec::new()); } pub fn add_implicits_of_record( @@ -797,7 +807,7 @@ impl<'a> ImplicitResolver<'a> { self.add_implicits_of_record_rec(subs, typ, meta.as_ref().map(|m| &**m), &mut Vec::new()); } - fn add_implicits_of_record_rec( + fn add_implicits_of_ident( &mut self, mut subs: &Substitution, typ: &RcType, @@ -821,30 +831,47 @@ impl<'a> ImplicitResolver<'a> { let opt = self.try_create_implicit(metadata, typ); - let mut typ = typ.clone(); if let Some(definition) = opt { let typ = subs.forall(forall_params.iter().cloned().collect(), typ.clone()); self.implicit_bindings .insert(subs, definition, &self.path, &typ); + + self.add_implicits_of_record_rec(subs, &typ, metadata, forall_params) } + } + fn add_implicits_of_record_rec( + &mut self, + mut subs: &Substitution, + typ: &RcType, + metadata: Option<&Metadata>, + forall_params: &mut Vec>, + ) { let forall_params_len_before = forall_params.len(); + let mut typ = typ.clone(); while let Type::Forall(params, next) = &*typ { forall_params.extend(params.iter().cloned()); typ = next.clone(); } - let raw_type = - match self - .alias_resolver - .remove_aliases(&self.environment, &mut subs, typ.clone()) - { - Ok(t) => t, - // Don't recurse into self recursive aliases - Err(_) => return, - }; + let t = self.alias_resolver.remove_aliases_predicate( + &self.environment, + &mut subs, + typ.clone(), + |alias| { + alias + .unresolved_type() + .flags() + .contains(Flags::HAS_IMPLICIT) + }, + ); + let raw_type = match t { + Ok(t) => t, + // Don't recurse into self recursive aliases + Err(_) => return, + }; match *raw_type { Type::Record(_) => { for field in raw_type.row_iter() { @@ -861,12 +888,7 @@ impl<'a> ImplicitResolver<'a> { typ: field.typ.clone(), }); - self.add_implicits_of_record_rec( - subs, - &field.typ, - field_metadata, - forall_params, - ); + self.add_implicits_of_ident(subs, &field.typ, field_metadata, forall_params); self.path.pop(); } diff --git a/tests/vm.rs b/tests/vm.rs index 016b46b21d..656e3462de 100644 --- a/tests/vm.rs +++ b/tests/vm.rs @@ -409,30 +409,6 @@ f 0 (\r -> { x = r #Int+ 1 }) 1i32 } -#[test] -fn overloaded_bindings() { - let _ = ::env_logger::try_init(); - let text = r#" -#[implicit] -let add_int x y = x #Int+ y -#[implicit] -let add_float x y = x #Float+ y - -let add ?f: [a -> a -> a] -> a -> a -> a = f - -{ x = add 1 2, y = add 1.0 2.0 } -"#; - let vm = make_vm(); - let result = run_expr::>(&vm, text); - match result.get_ref() { - ValueRef::Data(data) => { - assert_eq!(data.get(0).unwrap(), ValueRef::Int(3)); - assert_eq!(data.get(1).unwrap(), ValueRef::Float(3.0)); - } - _ => panic!(), - } -} - test_expr! { record_base_duplicate_fields, r#" { x = "" .. { x = 1 } }.x