Skip to content

Commit

Permalink
perf: Avoid recursing into non-implicit types
Browse files Browse the repository at this point in the history
Cheaply tracks wheter implicit types occur in a type at a very coarse
level. Many types such as `[Functor f] -> f a` which would not be
considered for implicit resolution are still considered to contain
implicits.
  • Loading branch information
Marwes committed May 17, 2019
1 parent d8c549b commit c35b29e
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 52 deletions.
1 change: 1 addition & 0 deletions base/src/types/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ bitflags! {
const HAS_GENERICS = 1 << 2;
const HAS_FORALL = 1 << 3;
const HAS_IDENTS = 1 << 4;
const HAS_IMPLICIT = 1 << 5;


const NEEDS_GENERALIZE =
Expand Down
92 changes: 75 additions & 17 deletions base/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1729,8 +1729,7 @@ impl<Id> TypeExt for ArcType<Id> {

fn new(typ: Type<Id, ArcType<Id>>) -> ArcType<Id> {
let flags = Flags::from_type(&typ);
let typ = Arc::new(ArcTypeInner { typ, flags });
ArcType { typ }
Self::with_flags(typ, flags)
}

fn strong_count(typ: &ArcType<Id>) -> usize {
Expand Down Expand Up @@ -1780,6 +1779,12 @@ impl<Id> From<Type<Id, ArcType<Id>>> for ArcType<Id> {
}
}

impl<Id> From<(Type<Id, ArcType<Id>>, Flags)> for ArcType<Id> {
fn from((typ, flags): (Type<Id, ArcType<Id>>, Flags)) -> ArcType<Id> {
ArcType::with_flags(typ, flags)
}
}

#[derive(Clone)]
pub struct TypeFieldIterator<'a, T: 'a> {
typ: &'a T,
Expand Down Expand Up @@ -2051,6 +2056,11 @@ where
}

impl<Id> ArcType<Id> {
fn with_flags(typ: Type<Id, ArcType<Id>>, flags: Flags) -> ArcType<Id> {
let typ = Arc::new(ArcTypeInner { typ, flags });
ArcType { typ }
}

pub fn set(into: &mut Self, typ: Type<Id, Self>)
where
Id: Clone,
Expand Down Expand Up @@ -2827,6 +2837,10 @@ macro_rules! forward_type_interner_methods {
$crate::expr!(self, $($tokens)+).intern(typ)
}

fn intern_flags(&mut self, typ: $crate::types::Type<$id, $typ>, flags: $crate::types::Flags) -> $typ {
$crate::expr!(self, $($tokens)+).intern_flags(typ, flags)
}

fn builtin(&mut self, typ: $crate::types::BuiltinType) -> $typ {
$crate::expr!(self, $($tokens)+).builtin(typ)
}
Expand Down Expand Up @@ -2925,8 +2939,15 @@ macro_rules! forward_type_interner_methods {
$crate::expr!(self, $($tokens)+).new_data_alias(data)
}

fn alias_group(&mut self, group: Vec<$crate::types::AliasData<$id, $typ>>) -> Vec<$crate::types::Alias<$id, $typ>> {
$crate::expr!(self, $($tokens)+).alias_group(group)
fn alias_group(
&mut self,
group: Vec<$crate::types::AliasData<$id, $typ>>,
is_implicit_iter: impl IntoIterator<Item = bool>
) -> Vec<$crate::types::Alias<$id, $typ>>
where
$typ: $crate::types::TypeExt<Id = $id>,
{
$crate::expr!(self, $($tokens)+).alias_group(group, is_implicit_iter)
}

/*
Expand Down Expand Up @@ -2988,6 +3009,8 @@ pub struct InternerVisitor<'i, F, T> {
}

pub trait TypeContext<Id, T> {
fn intern_flags(&mut self, typ: Type<Id, T>, flags: Flags) -> T;

fn intern(&mut self, typ: Type<Id, T>) -> T;

fn hole(&mut self) -> T {
Expand Down Expand Up @@ -3238,15 +3261,33 @@ pub trait TypeContext<Id, T> {
}
}

fn alias_group(&mut self, group: Vec<AliasData<Id, T>>) -> Vec<Alias<Id, T>> {
fn alias_group(
&mut self,
group: Vec<AliasData<Id, T>>,
is_implicit_iter: impl IntoIterator<Item = bool>,
) -> Vec<Alias<Id, T>>
where
T: TypeExt<Id = Id>,
{
let group = Arc::<[_]>::from(group);
(0..group.len())
.map(|index| Alias {
_typ: self.intern(Type::Alias(AliasRef {
.zip(is_implicit_iter)
.map(|(index, is_implicit)| {
let typ = Type::Alias(AliasRef {
index,
group: group.clone(),
})),
_marker: PhantomData,
});
let flags = Flags::from_type(&typ)
| (if is_implicit {
Flags::HAS_IMPLICIT
} else {
Flags::empty()
});

Alias {
_typ: self.intern_flags(typ, flags),
_marker: PhantomData,
}
})
.collect()
}
Expand Down Expand Up @@ -3285,11 +3326,15 @@ pub struct NullInterner;

impl<Id, T> TypeContext<Id, T> for NullInterner
where
T: From<Type<Id, T>>,
T: From<(Type<Id, T>, Flags)> + From<Type<Id, T>>,
{
fn intern(&mut self, typ: Type<Id, T>) -> T {
T::from(typ)
}

fn intern_flags(&mut self, typ: Type<Id, T>, flags: Flags) -> T {
T::from((typ, flags))
}
}

macro_rules! forward_to_cache {
Expand All @@ -3304,12 +3349,16 @@ macro_rules! forward_to_cache {

impl<Id, T> TypeContext<Id, T> for TypeCache<Id, T>
where
T: From<Type<Id, T>> + Clone,
T: From<(Type<Id, T>, Flags)> + From<Type<Id, T>> + Clone,
{
fn intern(&mut self, typ: Type<Id, T>) -> T {
T::from(typ)
}

fn intern_flags(&mut self, typ: Type<Id, T>, flags: Flags) -> T {
T::from((typ, flags))
}

forward_to_cache! {
hole opaque error int byte float string char
function_builtin array_builtin unit empty_row
Expand All @@ -3318,12 +3367,16 @@ where

impl<'a, Id, T> TypeContext<Id, T> for &'a TypeCache<Id, T>
where
T: From<Type<Id, T>> + Clone,
T: From<(Type<Id, T>, Flags)> + From<Type<Id, T>> + Clone,
{
fn intern(&mut self, typ: Type<Id, T>) -> T {
T::from(typ)
}

fn intern_flags(&mut self, typ: Type<Id, T>, flags: Flags) -> T {
T::from((typ, flags))
}

forward_to_cache! {
hole opaque error int byte float string char
function_builtin array_builtin unit empty_row
Expand Down Expand Up @@ -3376,19 +3429,19 @@ where

pub trait TypeContextAlloc: Sized {
type Id;
fn alloc(into: &mut Self, typ: Type<Self::Id, Self>);
fn alloc(into: &mut Self, typ: Type<Self::Id, Self>, flags: Flags);
}

impl TypeContextAlloc for ArcType {
type Id = Symbol;
fn alloc(into: &mut Self, typ: Type<Symbol, Self>) {
fn alloc(into: &mut Self, typ: Type<Symbol, Self>, flags: Flags) {
match Arc::get_mut(&mut into.typ) {
Some(into) => {
into.flags = Flags::from_type(&typ);
into.flags = flags;
into.typ = typ;
}
None => {
*into = Self::new(typ);
*into = Self::with_flags(typ, flags);
}
}
}
Expand Down Expand Up @@ -3446,9 +3499,14 @@ where
Id: Eq + Hash,
{
fn intern(&mut self, typ: Type<Id, T>) -> T {
let flags = Flags::from_type(&typ);
self.intern_flags(typ, flags)
}

fn intern_flags(&mut self, typ: Type<Id, T>, flags: Flags) -> T {
use std::collections::hash_map::Entry;

T::alloc(&mut self.scratch.0, typ);
T::alloc(&mut self.scratch.0, typ, flags);
match self.set.entry(self.scratch.clone()) {
Entry::Occupied(entry) => return entry.key().0.clone(),
Entry::Vacant(entry) => {
Expand Down
65 changes: 34 additions & 31 deletions check/src/implicits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use crate::base::{
pos::{self, BytePos, Span, Spanned},
resolve,
scoped_map::{self, ScopedMap},
symbol::Symbol,
types::{self, ArgType, BuiltinType, Generic, SymbolKey, Type, TypeContext, TypeExt},
symbol::{Symbol, SymbolRef},
types::{self, ArgType, BuiltinType, Flags, Type, TypeContext, TypeExt},
};

use crate::{
Expand All @@ -27,32 +27,32 @@ use crate::{
};

fn split_type<'a>(
subs: &'a Substitution<RcType>,
typ: &'a RcType,
subs: &'a Substitution<RcType>,
typ: &'a RcType,
) -> Option<(SymbolKey, Option<&'a RcType>)> {
let symbol = match **subs.real(typ) {
Type::App(ref id, ref args) => {
let symbol = match **subs.real(typ) {
Type::App(ref id, ref args) => {
return split_type(subs, id)
.map(|(k, _)| k)
.map(|key| (key, if args.len() == 1 { args.get(0) } else { None }));
}
Type::Function(ArgType::Implicit, _, ref ret_type) => {
.map(|(k, _)| k)
.map(|key| (key, if args.len() == 1 { args.get(0) } else { None }));
}
Type::Function(ArgType::Implicit, _, ref ret_type) => {
split_type(subs, ret_type)
// Usually the implicit argument will appear directly inside type whose `SymbolKey`
// that was returned so it is unlikely that partitition further
.map(|(s, _)| s)
}
Type::Function(ArgType::Explicit, ..) => {
Some(SymbolKey::Ref(BuiltinType::Function.symbol()))
}
Type::Skolem(ref skolem) => Some(SymbolKey::Owned(skolem.name.clone())),
Type::Ident(ref id) => Some(SymbolKey::Owned(id.clone())),
Type::Alias(ref alias) => Some(SymbolKey::Owned(alias.name.clone())),
Type::Builtin(ref builtin) => Some(SymbolKey::Ref(builtin.symbol())),
}
Type::Function(ArgType::Explicit, ..) => {
Some(SymbolKey::Ref(BuiltinType::Function.symbol()))
}
Type::Skolem(ref skolem) => Some(SymbolKey::Owned(skolem.name.clone())),
Type::Ident(ref id) => Some(SymbolKey::Owned(id.clone())),
Type::Alias(ref alias) => Some(SymbolKey::Owned(alias.name.clone())),
Type::Builtin(ref builtin) => Some(SymbolKey::Ref(builtin.symbol())),
Type::Forall(_, ref typ) => return split_type(subs, typ),
_ => None,
};
symbol.map(|s| (s, None))
_ => None,
};
symbol.map(|s| (s, None))
}

type ImplicitBinding = (Rc<[TypedIdent<Symbol, RcType>]>, RcType);
Expand Down Expand Up @@ -250,10 +250,10 @@ impl Partition<ImplicitBinding> {
let name = &path[0].name;
if let Some(t) = f(name) {
*typ = t;
}
}
}
}
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
Expand Down Expand Up @@ -764,7 +764,7 @@ impl<'a> ImplicitResolver<'a> {

pub fn on_stack_var(&mut self, subs: &Substitution<RcType>, id: &Symbol, typ: &RcType) {
self.add_implicits_of_record(subs, id, typ);
}
}

pub fn add_implicits_of_record(
&mut self,
Expand Down Expand Up @@ -792,6 +792,9 @@ impl<'a> ImplicitResolver<'a> {
forall_params: &mut Vec<Generic<Symbol>>,
) {
let typ = subs.real(typ);
if metadata.is_none() && !typ.flags().contains(Flags::HAS_IMPLICIT) {
return;
}

let opt = self.try_create_implicit(metadata, typ);

Expand Down Expand Up @@ -833,14 +836,14 @@ impl<'a> ImplicitResolver<'a> {
&mut subs,
typ.clone(),
) {
Ok(t) => t,
// Don't recurse into self recursive aliases
Err(_) => return,
Ok(t) => t,
// Don't recurse into self recursive aliases
Err(_) => return,
}
}
Ok(None) => typ,
Err(_) => return,
};
};
match *raw_type {
Type::Record(_) => {
for field in raw_type.row_iter() {
Expand All @@ -854,11 +857,11 @@ impl<'a> ImplicitResolver<'a> {
});

self.add_implicits_of_record_rec(
subs,
subs,
&field.typ,
field_metadata,
forall_params,
);
);

self.path.pop();
}
Expand Down Expand Up @@ -888,11 +891,11 @@ impl<'a> ImplicitResolver<'a> {
.map_or(false, |typename| {
let mut is_implicit_memo = self.is_implicit_memo.borrow_mut();
*is_implicit_memo.entry(typename.clone()).or_insert_with(|| {
self.metadata
self.metadata
.get(&*typename)
.or_else(|| self.environment.get_metadata(&typename))
.map_or(false, |m| has_implicit_attribute(m))
})
})
});
}

Expand Down
7 changes: 6 additions & 1 deletion check/src/typecheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2161,7 +2161,12 @@ impl<'a> Typecheck<'a> {
.map(|a| types::translate_alias(&a, |t| self.translate_rc_type(t)))
.collect(),
);
let alias_group = self.subs.alias_group(resolved_aliases);
let alias_group = self.subs.alias_group(
resolved_aliases,
bindings
.iter()
.map(|bind| bind.metadata.get_attribute("implicit").is_some()),
);
for (bind, alias) in bindings.iter_mut().zip(arc_alias_group) {
bind.finalized_alias = Some(alias);
}
Expand Down
4 changes: 1 addition & 3 deletions check/src/typecheck/generalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,7 @@ impl<'a, 'b> ::std::ops::DerefMut for TypeGeneralizer<'a, 'b> {
}

impl<'a, 'b> TypeContext<Symbol, RcType> for TypeGeneralizer<'a, 'b> {
fn intern(&mut self, typ: Type<Symbol, RcType>) -> RcType {
(&self.tc.subs).intern(typ)
}
gluon_base::forward_type_interner_methods!(Symbol, RcType, self_, &self_.tc.subs);
}

impl<'a, 'b> TypeGeneralizer<'a, 'b> {
Expand Down

0 comments on commit c35b29e

Please sign in to comment.