From 94c345b66c1f8c1197611f7478898f8b76052ada Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 4 Jan 2015 06:10:34 -0500 Subject: [PATCH 1/7] Convert astconv and friends to use object types, not generics. No need to compile all that stuff twice. Also, code reads so much nicer. --- src/librustc_typeck/astconv.rs | 222 +++++++++++++++------------------ 1 file changed, 103 insertions(+), 119 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1d62733875e..ea1577d52a3 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -70,7 +70,9 @@ use syntax::print::pprust; pub trait AstConv<'tcx> { fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>; + fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx>; + fn get_trait_def(&self, id: ast::DefId) -> Rc>; /// Return an (optional) substitution to convert bound type parameters that @@ -162,9 +164,9 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime) r } -pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( - this: &AC, - rscope: &RS, +pub fn opt_ast_region_to_region<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, default_span: Span, opt_lifetime: &Option) -> ty::Region { @@ -241,13 +243,12 @@ pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`, /// returns an appropriate set of substitutions for this particular reference to `I`. -fn ast_path_substs_for_ty<'tcx,AC,RS>( - this: &AC, - rscope: &RS, +fn ast_path_substs_for_ty<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, decl_generics: &ty::Generics<'tcx>, path: &ast::Path) -> Substs<'tcx> - where AC: AstConv<'tcx>, RS: RegionScope { let tcx = this.tcx(); @@ -285,16 +286,15 @@ fn ast_path_substs_for_ty<'tcx,AC,RS>( regions) } -fn create_substs_for_ast_path<'tcx,AC,RS>( - this: &AC, - rscope: &RS, +fn create_substs_for_ast_path<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, span: Span, decl_generics: &ty::Generics<'tcx>, self_ty: Option>, types: Vec>, regions: Vec) - -> Substs<'tcx> - where AC: AstConv<'tcx>, RS: RegionScope + -> Substs<'tcx> { let tcx = this.tcx(); @@ -408,13 +408,12 @@ struct ConvertedBinding<'tcx> { span: Span, } -fn convert_angle_bracketed_parameters<'tcx, AC, RS>(this: &AC, - rscope: &RS, - data: &ast::AngleBracketedParameterData) - -> (Vec, - Vec>, - Vec>) - where AC: AstConv<'tcx>, RS: RegionScope +fn convert_angle_bracketed_parameters<'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + data: &ast::AngleBracketedParameterData) + -> (Vec, + Vec>, + Vec>) { let regions: Vec<_> = data.lifetimes.iter() @@ -468,12 +467,11 @@ fn find_implied_output_region(input_tys: &[Ty], input_pats: Vec) (implied_output_region, lifetimes_for_params) } -fn convert_ty_with_lifetime_elision<'tcx,AC>(this: &AC, - implied_output_region: Option, - param_lifetimes: Vec<(String, uint)>, - ty: &ast::Ty) - -> Ty<'tcx> - where AC: AstConv<'tcx> +fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>, + implied_output_region: Option, + param_lifetimes: Vec<(String, uint)>, + ty: &ast::Ty) + -> Ty<'tcx> { match implied_output_region { Some(implied_output_region) => { @@ -490,10 +488,9 @@ fn convert_ty_with_lifetime_elision<'tcx,AC>(this: &AC, } } -fn convert_parenthesized_parameters<'tcx,AC>(this: &AC, - data: &ast::ParenthesizedParameterData) - -> Vec> - where AC: AstConv<'tcx> +fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>, + data: &ast::ParenthesizedParameterData) + -> Vec> { let binding_rscope = BindingRscope::new(); let inputs = data.inputs.iter() @@ -517,14 +514,13 @@ fn convert_parenthesized_parameters<'tcx,AC>(this: &AC, vec![input_ty, output] } -pub fn instantiate_poly_trait_ref<'tcx,AC,RS>( - this: &AC, - rscope: &RS, +pub fn instantiate_poly_trait_ref<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, ast_trait_ref: &ast::PolyTraitRef, self_ty: Option>, poly_projections: &mut Vec>) -> ty::PolyTraitRef<'tcx> - where AC: AstConv<'tcx>, RS: RegionScope { let mut projections = Vec::new(); @@ -545,14 +541,13 @@ pub fn instantiate_poly_trait_ref<'tcx,AC,RS>( /// /// If the `projections` argument is `None`, then assoc type bindings like `Foo` /// are disallowed. Otherwise, they are pushed onto the vector given. -pub fn instantiate_trait_ref<'tcx,AC,RS>( - this: &AC, - rscope: &RS, +pub fn instantiate_trait_ref<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, ast_trait_ref: &ast::TraitRef, self_ty: Option>, projections: Option<&mut Vec>>) -> Rc> - where AC: AstConv<'tcx>, RS: RegionScope { match ::lookup_def_tcx(this.tcx(), ast_trait_ref.path.span, ast_trait_ref.ref_id) { def::DefTrait(trait_def_id) => { @@ -573,15 +568,14 @@ pub fn instantiate_trait_ref<'tcx,AC,RS>( } } -fn ast_path_to_trait_ref<'a,'tcx,AC,RS>( - this: &AC, - rscope: &RS, +fn ast_path_to_trait_ref<'a,'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, trait_def_id: ast::DefId, self_ty: Option>, path: &ast::Path, mut projections: Option<&mut Vec>>) -> Rc> - where AC: AstConv<'tcx>, RS: RegionScope { debug!("ast_path_to_trait_ref {}", path); let trait_def = this.get_trait_def(trait_def_id); @@ -643,12 +637,11 @@ fn ast_path_to_trait_ref<'a,'tcx,AC,RS>( trait_ref } -pub fn ast_type_binding_to_projection_predicate<'tcx,AC>( - this: &AC, +pub fn ast_type_binding_to_projection_predicate<'tcx>( + this: &AstConv<'tcx>, trait_ref: Rc>, binding: &ConvertedBinding<'tcx>) -> Result, ErrorReported> - where AC : AstConv<'tcx> { // Given something like `U : SomeTrait`, we want to produce a // predicate like `::T = X`. This is somewhat @@ -686,9 +679,9 @@ pub fn ast_type_binding_to_projection_predicate<'tcx,AC>( }) } -pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( - this: &AC, - rscope: &RS, +pub fn ast_path_to_ty<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, did: ast::DefId, path: &ast::Path) -> TypeAndSubsts<'tcx> @@ -712,13 +705,12 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( /// and/or region variables are substituted. /// /// This is used when checking the constructor in struct literals. -pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>( - this: &AC, - rscope: &RS, +pub fn ast_path_to_ty_relaxed<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, did: ast::DefId, path: &ast::Path) -> TypeAndSubsts<'tcx> - where AC : AstConv<'tcx>, RS : RegionScope { let tcx = this.tcx(); let ty::TypeScheme { @@ -754,9 +746,9 @@ pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>( /// Converts the given AST type to a built-in type. A "built-in type" is, at /// present, either a core numeric type, a string, or `Box`. -pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( - this: &AC, - rscope: &RS, +pub fn ast_ty_to_builtin_ty<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, ast_ty: &ast::Ty) -> Option> { match ast_ty_to_prim_ty(this.tcx(), ast_ty) { @@ -807,12 +799,11 @@ pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( type TraitAndProjections<'tcx> = (ty::PolyTraitRef<'tcx>, Vec>); -fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, - rscope: &RS, - ty: &ast::Ty, - bounds: &[ast::TyParamBound]) - -> Result, ErrorReported> - where AC : AstConv<'tcx>, RS : RegionScope +fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + ty: &ast::Ty, + bounds: &[ast::TyParamBound]) + -> Result, ErrorReported> { /*! * In a type like `Foo + Send`, we want to wait to collect the @@ -878,14 +869,13 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, } } -fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC, - rscope: &RS, - span: Span, - trait_ref: ty::PolyTraitRef<'tcx>, - projection_bounds: Vec>, - bounds: &[ast::TyParamBound]) - -> Ty<'tcx> - where AC : AstConv<'tcx>, RS : RegionScope +fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + span: Span, + trait_ref: ty::PolyTraitRef<'tcx>, + projection_bounds: Vec>, + bounds: &[ast::TyParamBound]) + -> Ty<'tcx> { let existential_bounds = conv_existential_bounds(this, rscope, @@ -963,12 +953,11 @@ fn trait_defines_associated_type_named(this: &AstConv, trait_def.associated_type_names.contains(&assoc_name) } -fn qpath_to_ty<'tcx,AC,RS>(this: &AC, - rscope: &RS, - ast_ty: &ast::Ty, // the TyQPath - qpath: &ast::QPath) - -> Ty<'tcx> - where AC: AstConv<'tcx>, RS: RegionScope +fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + ast_ty: &ast::Ty, // the TyQPath + qpath: &ast::QPath) + -> Ty<'tcx> { debug!("qpath_to_ty(ast_ty={})", ast_ty.repr(this.tcx())); @@ -992,8 +981,8 @@ fn qpath_to_ty<'tcx,AC,RS>(this: &AC, // Parses the programmer's textual representation of a type into our // internal notion of a type. -pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( - this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> Ty<'tcx> +pub fn ast_ty_to_ty<'tcx>( + this: &AstConv<'tcx>, rscope: &RegionScope, ast_ty: &ast::Ty) -> Ty<'tcx> { debug!("ast_ty_to_ty(ast_ty={})", ast_ty.repr(this.tcx())); @@ -1205,10 +1194,12 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( return typ; } -pub fn ty_of_arg<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(this: &AC, rscope: &RS, - a: &ast::Arg, - expected_ty: Option>) - -> Ty<'tcx> { +pub fn ty_of_arg<'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + a: &ast::Arg, + expected_ty: Option>) + -> Ty<'tcx> +{ match a.ty.node { ast::TyInfer if expected_ty.is_some() => expected_ty.unwrap(), ast::TyInfer => this.ty_infer(a.ty.span), @@ -1221,14 +1212,13 @@ struct SelfInfo<'a, 'tcx> { explicit_self: &'a ast::ExplicitSelf, } -pub fn ty_of_method<'tcx, AC: AstConv<'tcx>>( - this: &AC, - unsafety: ast::Unsafety, - untransformed_self_ty: Ty<'tcx>, - explicit_self: &ast::ExplicitSelf, - decl: &ast::FnDecl, - abi: abi::Abi) - -> (ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) { +pub fn ty_of_method<'tcx>(this: &AstConv<'tcx>, + unsafety: ast::Unsafety, + untransformed_self_ty: Ty<'tcx>, + explicit_self: &ast::ExplicitSelf, + decl: &ast::FnDecl, + abi: abi::Abi) + -> (ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) { let self_info = Some(SelfInfo { untransformed_self_ty: untransformed_self_ty, explicit_self: explicit_self, @@ -1242,20 +1232,18 @@ pub fn ty_of_method<'tcx, AC: AstConv<'tcx>>( (bare_fn_ty, optional_explicit_self_category.unwrap()) } -pub fn ty_of_bare_fn<'tcx, AC: AstConv<'tcx>>(this: &AC, unsafety: ast::Unsafety, abi: abi::Abi, +pub fn ty_of_bare_fn<'tcx>(this: &AstConv<'tcx>, unsafety: ast::Unsafety, abi: abi::Abi, decl: &ast::FnDecl) -> ty::BareFnTy<'tcx> { let (bare_fn_ty, _) = ty_of_method_or_bare_fn(this, unsafety, abi, None, decl); bare_fn_ty } -fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>( - this: &AC, - unsafety: ast::Unsafety, - abi: abi::Abi, - opt_self_info: Option>, - decl: &ast::FnDecl) - -> (ty::BareFnTy<'tcx>, - Option) +fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>, + unsafety: ast::Unsafety, + abi: abi::Abi, + opt_self_info: Option>, + decl: &ast::FnDecl) + -> (ty::BareFnTy<'tcx>, Option) { debug!("ty_of_method_or_bare_fn"); @@ -1357,12 +1345,10 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>( }, explicit_self_category_result) } -fn determine_explicit_self_category<'a, 'tcx, AC: AstConv<'tcx>, - RS:RegionScope>( - this: &AC, - rscope: &RS, - self_info: &SelfInfo<'a, 'tcx>) - -> ty::ExplicitSelfCategory +fn determine_explicit_self_category<'a, 'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + self_info: &SelfInfo<'a, 'tcx>) + -> ty::ExplicitSelfCategory { return match self_info.explicit_self.node { ast::SelfStatic => ty::StaticExplicitSelfCategory, @@ -1439,8 +1425,8 @@ fn determine_explicit_self_category<'a, 'tcx, AC: AstConv<'tcx>, } } -pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>( - this: &AC, +pub fn ty_of_closure<'tcx>( + this: &AstConv<'tcx>, unsafety: ast::Unsafety, onceness: ast::Onceness, bounds: ty::ExistentialBounds<'tcx>, @@ -1501,9 +1487,9 @@ pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>( /// `ExistentialBounds` struct. The `main_trait_refs` argument specifies the `Foo` -- it is absent /// for closures. Eventually this should all be normalized, I think, so that there is no "main /// trait ref" and instead we just have a flat list of bounds as the existential type. -pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( - this: &AC, - rscope: &RS, +pub fn conv_existential_bounds<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, span: Span, principal_trait_ref: Option>, // None for boxed closures projection_bounds: Vec>, @@ -1517,13 +1503,12 @@ pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( this, rscope, span, principal_trait_ref, projection_bounds, partitioned_bounds) } -fn conv_ty_poly_trait_ref<'tcx, AC, RS>( - this: &AC, - rscope: &RS, +fn conv_ty_poly_trait_ref<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, span: Span, ast_bounds: &[ast::TyParamBound]) -> Ty<'tcx> - where AC: AstConv<'tcx>, RS:RegionScope { let mut partitioned_bounds = partition_bounds(this.tcx(), span, ast_bounds[]); @@ -1556,15 +1541,14 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>( } } -pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>( - this: &AC, - rscope: &RS, +pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, span: Span, principal_trait_ref: Option>, // None for boxed closures mut projection_bounds: Vec>, // Empty for boxed closures partitioned_bounds: PartitionedBounds) -> ty::ExistentialBounds<'tcx> - where AC: AstConv<'tcx>, RS:RegionScope { let PartitionedBounds { builtin_bounds, trait_bounds, @@ -1657,9 +1641,9 @@ fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>, /// A version of `compute_opt_region_bound` for use where some region bound is required /// (existential types, basically). Reports an error if no region bound can be derived and we are /// in an `rscope` that does not provide a default. -fn compute_region_bound<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( - this: &AC, - rscope: &RS, +fn compute_region_bound<'tcx>( + this: &AstConv<'tcx>, + rscope: &RegionScope, span: Span, region_bounds: &[&ast::Lifetime], principal_trait_ref: Option>, // None for closures From 95ee339bd1785ca1918f332c77ed5804b69588c8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 4 Jan 2015 06:37:49 -0500 Subject: [PATCH 2/7] Stop writing code that is (unnecessarily) generic over any AstConv in collect, just hard-code the ccx. --- src/librustc_typeck/collect.rs | 87 ++++++++++++++++------------------ 1 file changed, 41 insertions(+), 46 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7c88404eb64..867fdd36b34 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -636,7 +636,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { debug!("trait_def: ident={} trait_def={}", it.ident.repr(ccx.tcx), - trait_def.repr(ccx.tcx())); + trait_def.repr(ccx.tcx)); for trait_method in trait_methods.iter() { let self_type = ty::mk_self_type(tcx); @@ -1108,14 +1108,13 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn ty_generics_for_fn_or_method<'tcx,AC>( - this: &AC, - generics: &ast::Generics, - base_generics: ty::Generics<'tcx>) - -> ty::Generics<'tcx> - where AC: AstConv<'tcx> { +fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, + generics: &ast::Generics, + base_generics: ty::Generics<'tcx>) + -> ty::Generics<'tcx> +{ let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics); - ty_generics(this, + ty_generics(ccx, subst::FnSpace, early_lifetimes[], generics.ty_params[], @@ -1124,11 +1123,11 @@ fn ty_generics_for_fn_or_method<'tcx,AC>( } // Add the Sized bound, unless the type parameter is marked as `?Sized`. -fn add_unsized_bound<'tcx,AC>(this: &AC, +fn add_unsized_bound<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, bounds: &mut ty::BuiltinBounds, ast_bounds: &[ast::TyParamBound], span: Span) - where AC: AstConv<'tcx> { +{ // Try to find an unbound in bounds. let mut unbound = None; for ab in ast_bounds.iter() { @@ -1137,24 +1136,24 @@ fn add_unsized_bound<'tcx,AC>(this: &AC, assert!(ptr.bound_lifetimes.is_empty()); unbound = Some(ptr.trait_ref.clone()); } else { - this.tcx().sess.span_err(span, "type parameter has more than one relaxed default \ + ccx.tcx.sess.span_err(span, "type parameter has more than one relaxed default \ bound, only one is supported"); } } } - let kind_id = this.tcx().lang_items.require(SizedTraitLangItem); + let kind_id = ccx.tcx.lang_items.require(SizedTraitLangItem); match unbound { Some(ref tpb) => { // FIXME(#8559) currently requires the unbound to be built-in. - let trait_def_id = ty::trait_ref_to_def_id(this.tcx(), tpb); + let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, tpb); match kind_id { Ok(kind_id) if trait_def_id != kind_id => { - this.tcx().sess.span_warn(span, + ccx.tcx.sess.span_warn(span, "default bound relaxed for a type parameter, but \ this does nothing because the given bound is not \ a default. Only `?Sized` is supported"); - ty::try_add_builtin_trait(this.tcx(), + ty::try_add_builtin_trait(ccx.tcx, kind_id, bounds); } @@ -1162,27 +1161,26 @@ fn add_unsized_bound<'tcx,AC>(this: &AC, } } _ if kind_id.is_ok() => { - ty::try_add_builtin_trait(this.tcx(), kind_id.unwrap(), bounds); + ty::try_add_builtin_trait(ccx.tcx, kind_id.unwrap(), bounds); } // No lang item for Sized, so we can't add it as a bound. None => {} } } -fn ty_generics<'tcx,AC>(this: &AC, +fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, space: subst::ParamSpace, lifetime_defs: &[ast::LifetimeDef], types: &[ast::TyParam], base_generics: ty::Generics<'tcx>, where_clause: &ast::WhereClause) -> ty::Generics<'tcx> - where AC: AstConv<'tcx> { let mut result = base_generics; for (i, l) in lifetime_defs.iter().enumerate() { let bounds = l.bounds.iter() - .map(|l| ast_region_to_region(this.tcx(), l)) + .map(|l| ast_region_to_region(ccx.tcx, l)) .collect(); let def = ty::RegionParameterDef { name: l.lifetime.name, space: space, @@ -1197,25 +1195,25 @@ fn ty_generics<'tcx,AC>(this: &AC, // Now create the real type parameters. for (i, param) in types.iter().enumerate() { - let def = get_or_create_type_parameter_def(this, + let def = get_or_create_type_parameter_def(ccx, space, param, i as u32); debug!("ty_generics: def for type param: {}, {}", - def.repr(this.tcx()), + def.repr(ccx.tcx), space); result.types.push(space, def); } // Just for fun, also push the bounds from the type parameters // into the predicates list. This is currently kind of non-DRY. - create_predicates(this.tcx(), &mut result, space); + create_predicates(ccx.tcx, &mut result, space); // Add the bounds not associated with a type parameter for predicate in where_clause.predicates.iter() { match predicate { &ast::WherePredicate::BoundPredicate(ref bound_pred) => { - let ty = ast_ty_to_ty(this, &ExplicitRscope, &*bound_pred.bounded_ty); + let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &*bound_pred.bounded_ty); for bound in bound_pred.bounds.iter() { match bound { @@ -1223,7 +1221,7 @@ fn ty_generics<'tcx,AC>(this: &AC, let mut projections = Vec::new(); let trait_ref = astconv::instantiate_poly_trait_ref( - this, + ccx, &ExplicitRscope, poly_trait_ref, Some(ty), @@ -1238,7 +1236,7 @@ fn ty_generics<'tcx,AC>(this: &AC, } &ast::TyParamBound::RegionTyParamBound(ref lifetime) => { - let region = ast_region_to_region(this.tcx(), lifetime); + let region = ast_region_to_region(ccx.tcx, lifetime); let pred = ty::Binder(ty::OutlivesPredicate(ty, region)); result.predicates.push(space, ty::Predicate::TypeOutlives(pred)) } @@ -1247,9 +1245,9 @@ fn ty_generics<'tcx,AC>(this: &AC, } &ast::WherePredicate::RegionPredicate(ref region_pred) => { - let r1 = ast_region_to_region(this.tcx(), ®ion_pred.lifetime); + let r1 = ast_region_to_region(ccx.tcx, ®ion_pred.lifetime); for bound in region_pred.bounds.iter() { - let r2 = ast_region_to_region(this.tcx(), bound); + let r2 = ast_region_to_region(ccx.tcx, bound); let pred = ty::Binder(ty::OutlivesPredicate(r1, r2)); result.predicates.push(space, ty::Predicate::RegionOutlives(pred)) } @@ -1257,7 +1255,7 @@ fn ty_generics<'tcx,AC>(this: &AC, &ast::WherePredicate::EqPredicate(ref eq_pred) => { // FIXME(#20041) - this.tcx().sess.span_bug(eq_pred.span, + ccx.tcx.sess.span_bug(eq_pred.span, "Equality constraints are not yet \ implemented (#20041)") } @@ -1292,34 +1290,33 @@ fn ty_generics<'tcx,AC>(this: &AC, } } -fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC, +fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, space: subst::ParamSpace, param: &ast::TyParam, index: u32) -> ty::TypeParameterDef<'tcx> - where AC: AstConv<'tcx> { - match this.tcx().ty_param_defs.borrow().get(¶m.id) { + match ccx.tcx.ty_param_defs.borrow().get(¶m.id) { Some(d) => { return (*d).clone(); } None => { } } let param_ty = ty::ParamTy::new(space, index, param.ident.name); - let bounds = compute_bounds(this, - param_ty.to_ty(this.tcx()), + let bounds = compute_bounds(ccx, + param_ty.to_ty(ccx.tcx), param.bounds[], SizedByDefault::Yes, param.span); let default = match param.default { None => None, Some(ref path) => { - let ty = ast_ty_to_ty(this, &ExplicitRscope, &**path); + let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &**path); let cur_idx = index; ty::walk_ty(ty, |t| { match t.sty { ty::ty_param(p) => if p.idx > cur_idx { - span_err!(this.tcx().sess, path.span, E0128, + span_err!(ccx.tcx.sess, path.span, E0128, "type parameters with a default cannot use \ forward declared identifiers"); }, @@ -1340,7 +1337,7 @@ fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC, default: default }; - this.tcx().ty_param_defs.borrow_mut().insert(param.id, def.clone()); + ccx.tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone()); def } @@ -1350,26 +1347,25 @@ enum SizedByDefault { Yes, No } /// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or /// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the /// built-in trait (formerly known as kind): Send. -fn compute_bounds<'tcx,AC>(this: &AC, +fn compute_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, param_ty: ty::Ty<'tcx>, ast_bounds: &[ast::TyParamBound], sized_by_default: SizedByDefault, span: Span) -> ty::ParamBounds<'tcx> - where AC: AstConv<'tcx> { - let mut param_bounds = conv_param_bounds(this, + let mut param_bounds = conv_param_bounds(ccx, span, param_ty, ast_bounds); if let SizedByDefault::Yes = sized_by_default { - add_unsized_bound(this, + add_unsized_bound(ccx, &mut param_bounds.builtin_bounds, ast_bounds, span); - check_bounds_compatible(this.tcx(), + check_bounds_compatible(ccx.tcx, param_ty, ¶m_bounds, span); @@ -1404,24 +1400,23 @@ fn check_bounds_compatible<'tcx>(tcx: &ty::ctxt<'tcx>, } } -fn conv_param_bounds<'tcx,AC>(this: &AC, +fn conv_param_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, span: Span, param_ty: ty::Ty<'tcx>, ast_bounds: &[ast::TyParamBound]) -> ty::ParamBounds<'tcx> - where AC: AstConv<'tcx> { let astconv::PartitionedBounds { builtin_bounds, trait_bounds, region_bounds } = - astconv::partition_bounds(this.tcx(), span, ast_bounds.as_slice()); + astconv::partition_bounds(ccx.tcx, span, ast_bounds.as_slice()); let mut projection_bounds = Vec::new(); let trait_bounds: Vec = trait_bounds.into_iter() .map(|bound| { - astconv::instantiate_poly_trait_ref(this, + astconv::instantiate_poly_trait_ref(ccx, &ExplicitRscope, bound, Some(param_ty), @@ -1430,7 +1425,7 @@ fn conv_param_bounds<'tcx,AC>(this: &AC, .collect(); let region_bounds: Vec = region_bounds.into_iter() - .map(|r| ast_region_to_region(this.tcx(), r)) + .map(|r| ast_region_to_region(ccx.tcx, r)) .collect(); ty::ParamBounds { region_bounds: region_bounds, From 2ccab193afb54febda3777f67f56d330b6ae8a2c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 5 Jan 2015 04:24:00 -0500 Subject: [PATCH 3/7] Introduce a CollectCtxt and impl AstConv on *that*. Also make all fns in collect private except the public entry point. --- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/collect.rs | 122 +++++++++++++++++-------------- src/librustc_typeck/lib.rs | 4 +- 3 files changed, 70 insertions(+), 58 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 854de823511..8b62c55ba31 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4939,7 +4939,7 @@ pub fn check_enum_variants(ccx: &CrateCtxt, Some(i) => { span_err!(ccx.tcx.sess, v.span, E0081, "discriminant value `{}` already exists", disr_vals[i]); - span_note!(ccx.tcx.sess, ccx.tcx().map.span(variants[i].id.node), + span_note!(ccx.tcx.sess, ccx.tcx.map.span(variants[i].id.node), "conflicting discriminant here") } None => {} diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 867fdd36b34..6f5eccfa198 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -40,11 +40,12 @@ use middle::ty::{AsPredicate, ImplContainer, ImplOrTraitItemContainer, TraitCont use middle::ty::{self, RegionEscape, Ty, TypeScheme}; use middle::ty_fold::{self, TypeFolder, TypeFoldable}; use middle::infer; +use no_params; use rscope::*; -use {CrateCtxt, no_params, write_ty_to_tcx}; use util::nodemap::{FnvHashMap, FnvHashSet}; use util::ppaux; use util::ppaux::{Repr,UserString}; +use write_ty_to_tcx; use std::rc::Rc; @@ -61,13 +62,8 @@ use syntax::visit; /////////////////////////////////////////////////////////////////////////// // Main entry point -pub fn collect_item_types(ccx: &CrateCtxt) { - fn collect_intrinsic_type(ccx: &CrateCtxt, - lang_item: ast::DefId) { - let ty::TypeScheme { ty, .. } = - ccx.get_item_type_scheme(lang_item); - ccx.tcx.intrinsic_defs.borrow_mut().insert(lang_item, ty); - } +pub fn collect_item_types(tcx: &ty::ctxt) { + let ccx = &CollectCtxt { tcx: tcx }; match ccx.tcx.lang_items.ty_desc() { Some(id) => { collect_intrinsic_type(ccx, id); } @@ -85,13 +81,29 @@ pub fn collect_item_types(ccx: &CrateCtxt) { visit::walk_crate(&mut visitor, ccx.tcx.map.krate()); } +/////////////////////////////////////////////////////////////////////////// + +struct CollectCtxt<'a,'tcx:'a> { + tcx: &'a ty::ctxt<'tcx>, +} + +/////////////////////////////////////////////////////////////////////////// +// Zeroth phase: collect types of intrinsics + +fn collect_intrinsic_type(ccx: &CollectCtxt, + lang_item: ast::DefId) { + let ty::TypeScheme { ty, .. } = + ccx.get_item_type_scheme(lang_item); + ccx.tcx.intrinsic_defs.borrow_mut().insert(lang_item, ty); +} + /////////////////////////////////////////////////////////////////////////// // First phase: just collect *trait definitions* -- basically, the set // of type parameters and supertraits. This is information we need to // know later when parsing field defs. struct CollectTraitDefVisitor<'a, 'tcx: 'a> { - ccx: &'a CrateCtxt<'a, 'tcx> + ccx: &'a CollectCtxt<'a, 'tcx> } impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectTraitDefVisitor<'a, 'tcx> { @@ -112,7 +124,7 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectTraitDefVisitor<'a, 'tcx> { // Second phase: collection proper. struct CollectItemTypesVisitor<'a, 'tcx: 'a> { - ccx: &'a CrateCtxt<'a, 'tcx> + ccx: &'a CollectCtxt<'a, 'tcx> } impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> { @@ -133,13 +145,13 @@ pub trait ToTy<'tcx> { fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx>; } -impl<'a,'tcx> ToTy<'tcx> for CrateCtxt<'a,'tcx> { +impl<'a,'tcx> ToTy<'tcx> for CollectCtxt<'a,'tcx> { fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx> { ast_ty_to_ty(self, rs, ast_ty) } } -impl<'a, 'tcx> AstConv<'tcx> for CrateCtxt<'a, 'tcx> { +impl<'a, 'tcx> AstConv<'tcx> for CollectCtxt<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx } fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx> { @@ -181,7 +193,7 @@ impl<'a, 'tcx> AstConv<'tcx> for CrateCtxt<'a, 'tcx> { } } -pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn get_enum_variant_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, enum_ty: Ty<'tcx>, variants: &[P], generics: &ast::Generics) { @@ -226,7 +238,7 @@ pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, trait_id: ast::NodeId, trait_def: &ty::TraitDef<'tcx>) { let tcx = ccx.tcx; @@ -322,7 +334,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } - fn make_method_ty<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, m: &ty::Method<'tcx>) { + fn make_method_ty<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, m: &ty::Method<'tcx>) { ccx.tcx.tcache.borrow_mut().insert( m.def_id, TypeScheme { @@ -330,7 +342,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty: ty::mk_bare_fn(ccx.tcx, Some(m.def_id), ccx.tcx.mk_bare_fn(m.fty.clone())) }); } - fn ty_method_of_trait_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + fn ty_method_of_trait_method<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, trait_id: ast::NodeId, trait_generics: &ty::Generics<'tcx>, _trait_items: &[ast::TraitItem], @@ -372,7 +384,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -pub fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn convert_field<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, struct_generics: &ty::Generics<'tcx>, v: &ast::StructField, origin: ast::DefId) -> ty::field_ty { @@ -405,7 +417,7 @@ pub fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn convert_associated_type<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, trait_def: &ty::TraitDef<'tcx>, associated_type: &ast::AssociatedType) { @@ -422,7 +434,7 @@ fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty::TypeTraitItem(associated_type)); } -fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, +fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>, container: ImplOrTraitItemContainer, mut ms: I, untransformed_rcvr_ty: Ty<'tcx>, @@ -469,7 +481,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, .insert(mty.def_id, ty::MethodTraitItem(mty)); } - fn ty_of_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + fn ty_of_method<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, container: ImplOrTraitItemContainer, m: &ast::Method, untransformed_rcvr_ty: Ty<'tcx>, @@ -506,7 +518,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, } } -pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, +fn ensure_no_ty_param_bounds(ccx: &CollectCtxt, span: Span, generics: &ast::Generics, thing: &'static str) { @@ -535,7 +547,7 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, } } -pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { +fn convert(ccx: &CollectCtxt, it: &ast::Item) { let tcx = ccx.tcx; debug!("convert: item {} with id {}", token::get_ident(it.ident), it.id); match it.node { @@ -706,7 +718,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { } } -pub fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn convert_struct<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, struct_def: &ast::StructDef, scheme: ty::TypeScheme<'tcx>, id: ast::NodeId) { @@ -773,7 +785,7 @@ pub fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -pub fn convert_foreign(ccx: &CrateCtxt, i: &ast::ForeignItem) { +fn convert_foreign(ccx: &CollectCtxt, i: &ast::ForeignItem) { // As above, this call populates the type table with the converted // type of the foreign item. We simply write it into the node type // table. @@ -790,7 +802,7 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: &ast::ForeignItem) { ccx.tcx.tcache.borrow_mut().insert(local_def(i.id), scheme); } -fn get_trait_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn get_trait_def<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, trait_id: ast::DefId) -> Rc> { if trait_id.krate != ast::LOCAL_CRATE { @@ -806,7 +818,7 @@ fn get_trait_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, it: &ast::Item) -> Rc> { @@ -872,7 +884,7 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, return trait_def; - fn mk_trait_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + fn mk_trait_substs<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, generics: &ast::Generics) -> subst::Substs<'tcx> { @@ -903,7 +915,7 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) +fn ty_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, it: &ast::Item) -> ty::TypeScheme<'tcx> { let def_id = local_def(it.id); let tcx = ccx.tcx; @@ -985,7 +997,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) } } -pub fn ty_of_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn ty_of_foreign_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, it: &ast::ForeignItem, abi: abi::Abi) -> ty::TypeScheme<'tcx> { @@ -1006,7 +1018,7 @@ pub fn ty_of_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, generics: &ast::Generics) -> ty::Generics<'tcx> { ty_generics(ccx, @@ -1017,7 +1029,7 @@ fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, &generics.where_clause) } -fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, trait_id: ast::NodeId, substs: &'tcx subst::Substs<'tcx>, ast_generics: &ast::Generics, @@ -1077,7 +1089,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, return generics; - fn predicates_for_associated_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + fn predicates_for_associated_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, self_trait_ref: &Rc>, trait_items: &[ast::TraitItem]) -> Vec> @@ -1108,7 +1120,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, +fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, generics: &ast::Generics, base_generics: ty::Generics<'tcx>) -> ty::Generics<'tcx> @@ -1123,7 +1135,7 @@ fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } // Add the Sized bound, unless the type parameter is marked as `?Sized`. -fn add_unsized_bound<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, +fn add_unsized_bound<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, bounds: &mut ty::BuiltinBounds, ast_bounds: &[ast::TyParamBound], span: Span) @@ -1168,7 +1180,7 @@ fn add_unsized_bound<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } } -fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, +fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, space: subst::ParamSpace, lifetime_defs: &[ast::LifetimeDef], types: &[ast::TyParam], @@ -1290,7 +1302,7 @@ fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } } -fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, +fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, space: subst::ParamSpace, param: &ast::TyParam, index: u32) @@ -1347,7 +1359,7 @@ enum SizedByDefault { Yes, No } /// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or /// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the /// built-in trait (formerly known as kind): Send. -fn compute_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, +fn compute_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, param_ty: ty::Ty<'tcx>, ast_bounds: &[ast::TyParamBound], sized_by_default: SizedByDefault, @@ -1400,7 +1412,7 @@ fn check_bounds_compatible<'tcx>(tcx: &ty::ctxt<'tcx>, } } -fn conv_param_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, +fn conv_param_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, span: Span, param_ty: ty::Ty<'tcx>, ast_bounds: &[ast::TyParamBound]) @@ -1435,7 +1447,7 @@ fn conv_param_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } } -pub fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, +fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, decl: &ast::FnDecl, def_id: ast::DefId, ast_generics: &ast::Generics, @@ -1487,9 +1499,9 @@ pub fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, return scheme; } -pub fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - ty_generics: &ty::Generics<'tcx>) - -> subst::Substs<'tcx> +fn mk_item_substs<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, + ty_generics: &ty::Generics<'tcx>) + -> subst::Substs<'tcx> { let types = ty_generics.types.map( @@ -1509,14 +1521,14 @@ pub fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, /// comes back to check after the fact that explicit type the user /// wrote actually matches what the pre-defined option said. fn check_method_self_type<'a, 'tcx, RS:RegionScope>( - crate_context: &CrateCtxt<'a, 'tcx>, + ccx: &CollectCtxt<'a, 'tcx>, rs: &RS, required_type: Ty<'tcx>, explicit_self: &ast::ExplicitSelf, body_id: ast::NodeId) { if let ast::SelfExplicit(ref ast_type, _) = explicit_self.node { - let typ = crate_context.to_ty(rs, &**ast_type); + let typ = ccx.to_ty(rs, &**ast_type); let base_type = match typ.sty { ty::ty_ptr(tm) | ty::ty_rptr(_, tm) => tm.ty, ty::ty_uniq(typ) => typ, @@ -1532,27 +1544,27 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( assert!(!base_type.has_regions_escaping_depth(1)); let required_type_free = liberate_early_bound_regions( - crate_context.tcx, body_scope, + ccx.tcx, body_scope, &ty::liberate_late_bound_regions( - crate_context.tcx, body_scope, &ty::Binder(required_type))); + ccx.tcx, body_scope, &ty::Binder(required_type))); // The "base type" comes from the impl. It too may have late-bound // regions from the method. assert!(!base_type.has_regions_escaping_depth(1)); let base_type_free = liberate_early_bound_regions( - crate_context.tcx, body_scope, + ccx.tcx, body_scope, &ty::liberate_late_bound_regions( - crate_context.tcx, body_scope, &ty::Binder(base_type))); + ccx.tcx, body_scope, &ty::Binder(base_type))); debug!("required_type={} required_type_free={} \ base_type={} base_type_free={}", - required_type.repr(crate_context.tcx), - required_type_free.repr(crate_context.tcx), - base_type.repr(crate_context.tcx), - base_type_free.repr(crate_context.tcx)); - let infcx = infer::new_infer_ctxt(crate_context.tcx); - drop(::require_same_types(crate_context.tcx, + required_type.repr(ccx.tcx), + required_type_free.repr(ccx.tcx), + base_type.repr(ccx.tcx), + base_type_free.repr(ccx.tcx)); + let infcx = infer::new_infer_ctxt(ccx.tcx); + drop(::require_same_types(ccx.tcx, Some(&infcx), false, explicit_self.span, @@ -1560,7 +1572,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( required_type_free, || { format!("mismatched self type: expected `{}`", - ppaux::ty_to_string(crate_context.tcx, required_type)) + ppaux::ty_to_string(ccx.tcx, required_type)) })); infcx.resolve_regions_and_report_errors(body_id); } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 48f9b129719..3146a118139 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -119,7 +119,7 @@ struct TypeAndSubsts<'tcx> { struct CrateCtxt<'a, 'tcx: 'a> { // A mapping from method call sites to traits that have that method. trait_map: ty::TraitMap, - tcx: &'a ty::ctxt<'tcx> + tcx: &'a ty::ctxt<'tcx>, } // Functions that write types into the node type table @@ -320,7 +320,7 @@ pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) { }; time(time_passes, "type collecting", (), |_| - collect::collect_item_types(&ccx)); + collect::collect_item_types(tcx)); // this ensures that later parts of type checking can assume that items // have valid types and not error From 9989288438e979ea256fa746e2fe3f7cdc00b001 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 5 Jan 2015 05:36:41 -0500 Subject: [PATCH 4/7] Permit bindings of (and references to) associated types defined in supertraits. --- src/librustc_typeck/astconv.rs | 60 +++++++++++++++---- ...pe-projection-from-multiple-supertraits.rs | 41 +++++++++++++ ...ociated-type-projection-from-supertrait.rs | 56 +++++++++++++++++ ...s-binding-to-type-defined-in-supertrait.rs | 53 ++++++++++++++++ .../associated-types-iterator-binding.rs | 27 +++++++++ 5 files changed, 224 insertions(+), 13 deletions(-) create mode 100644 src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs create mode 100644 src/test/compile-fail/associated-type-projection-from-supertrait.rs create mode 100644 src/test/compile-fail/associated-types-binding-to-type-defined-in-supertrait.rs create mode 100644 src/test/run-pass/associated-types-iterator-binding.rs diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index ea1577d52a3..e216338b1e3 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -53,7 +53,8 @@ use middle::def; use middle::resolve_lifetime as rl; use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; use middle::subst::{VecPerParamSpace}; -use middle::ty::{self, RegionEscape, Ty}; +use middle::traits; +use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty}; use rscope::{self, UnelidableRscope, RegionScope, SpecificRscope, ShiftedRscope, BindingRscope}; use TypeAndSubsts; @@ -637,7 +638,7 @@ fn ast_path_to_trait_ref<'a,'tcx>( trait_ref } -pub fn ast_type_binding_to_projection_predicate<'tcx>( +fn ast_type_binding_to_projection_predicate<'tcx>( this: &AstConv<'tcx>, trait_ref: Rc>, binding: &ConvertedBinding<'tcx>) @@ -659,20 +660,56 @@ pub fn ast_type_binding_to_projection_predicate<'tcx>( // // We want to produce `>::T == foo`. - // FIXME(#19541): supertrait upcasting not actually impl'd :) + // Simple case: X is defined in the current trait. + if trait_defines_associated_type_named(this, trait_ref.def_id, binding.item_name) { + return Ok(ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { + trait_ref: trait_ref, + item_name: binding.item_name, + }, + ty: binding.ty, + }); + } - if !trait_defines_associated_type_named(this, trait_ref.def_id, binding.item_name) { + // Otherwise, we have to walk through the supertraits to find those that do. + let mut candidates: Vec<_> = + traits::supertraits(this.tcx(), trait_ref.to_poly_trait_ref()) + .filter(|r| trait_defines_associated_type_named(this, r.def_id(), binding.item_name)) + .collect(); + + if candidates.len() > 1 { this.tcx().sess.span_err( binding.span, - format!("no associated type `{}` defined in `{}`", + format!("ambiguous associated type: `{}` defined in multiple supertraits `{}`", token::get_name(binding.item_name), - trait_ref.user_string(this.tcx())).as_slice()); + candidates.user_string(this.tcx())).as_slice()); + return Err(ErrorReported); + } + + let candidate = match candidates.pop() { + Some(c) => c, + None => { + this.tcx().sess.span_err( + binding.span, + format!("no associated type `{}` defined in `{}`", + token::get_name(binding.item_name), + trait_ref.user_string(this.tcx())).as_slice()); + return Err(ErrorReported); + } + }; + + if ty::binds_late_bound_regions(this.tcx(), &candidate) { + this.tcx().sess.span_err( + binding.span, + format!("associated type `{}` defined in higher-ranked supertrait `{}`", + token::get_name(binding.item_name), + candidate.user_string(this.tcx())).as_slice()); return Err(ErrorReported); } Ok(ty::ProjectionPredicate { projection_ty: ty::ProjectionTy { - trait_ref: trait_ref, + trait_ref: candidate.0, item_name: binding.item_name, }, ty: binding.ty, @@ -899,6 +936,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, { let tcx = this.tcx(); let ty_param_def_id = provenance.def_id(); + let mut suitable_bounds: Vec<_>; let ty_param_name: ast::Name; { // contain scope of refcell: @@ -906,13 +944,9 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, let ty_param_def = &ty_param_defs[ty_param_def_id.node]; ty_param_name = ty_param_def.name; - // FIXME(#19541): we should consider associated types in - // super-traits. Probably by elaborating the bounds. - + // FIXME(#20300) -- search where clauses, not bounds suitable_bounds = - ty_param_def.bounds.trait_bounds // FIXME(#20300) -- search where clauses, not bounds - .iter() - .cloned() + traits::transitive_bounds(tcx, ty_param_def.bounds.trait_bounds.as_slice()) .filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name)) .collect(); } diff --git a/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs b/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs new file mode 100644 index 00000000000..553e36f0e62 --- /dev/null +++ b/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs @@ -0,0 +1,41 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test equality constraints in a where clause where the type being +// equated appears in a supertrait. + +#![feature(associated_types)] + +pub trait Vehicle { + type Color; + + fn go(&self) { } +} + +pub trait Box { + type Color; + + fn mail(&self) { } +} + +pub trait BoxCar : Box + Vehicle { +} + +fn dent(c: C, color: C::Color) { + //~^ ERROR ambiguous associated type `Color` in bounds of `C` + //~| NOTE could derive from `Vehicle` + //~| NOTE could derive from `Box` +} + +fn dent_object(c: BoxCar) { + //~^ ERROR ambiguous associated type +} + +pub fn main() { } diff --git a/src/test/compile-fail/associated-type-projection-from-supertrait.rs b/src/test/compile-fail/associated-type-projection-from-supertrait.rs new file mode 100644 index 00000000000..01f9bd3541f --- /dev/null +++ b/src/test/compile-fail/associated-type-projection-from-supertrait.rs @@ -0,0 +1,56 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test equality constraints in a where clause where the type being +// equated appears in a supertrait. + +#![feature(associated_types)] + +pub trait Vehicle { + type Color; + + fn go(&self) { } +} + +pub trait Car : Vehicle { + fn honk(&self) { } + fn chip_paint(&self, c: Self::Color) { } +} + +/////////////////////////////////////////////////////////////////////////// + +struct Black; +struct ModelT; +impl Vehicle for ModelT { type Color = Black; } +impl Car for ModelT { } + +/////////////////////////////////////////////////////////////////////////// + +struct Blue; +struct ModelU; +impl Vehicle for ModelU { type Color = Blue; } +impl Car for ModelU { } + +/////////////////////////////////////////////////////////////////////////// + +fn dent(c: C, color: C::Color) { c.chip_paint(color) } +fn a() { dent(ModelT, Black); } +fn b() { dent(ModelT, Blue); } //~ ERROR type mismatch +fn c() { dent(ModelU, Black); } //~ ERROR type mismatch +fn d() { dent(ModelU, Blue); } + +/////////////////////////////////////////////////////////////////////////// + +fn e() { ModelT.chip_paint(Black); } +fn f() { ModelT.chip_paint(Blue); } //~ ERROR mismatched types +fn g() { ModelU.chip_paint(Black); } //~ ERROR mismatched types +fn h() { ModelU.chip_paint(Blue); } + +pub fn main() { } diff --git a/src/test/compile-fail/associated-types-binding-to-type-defined-in-supertrait.rs b/src/test/compile-fail/associated-types-binding-to-type-defined-in-supertrait.rs new file mode 100644 index 00000000000..a362529bee8 --- /dev/null +++ b/src/test/compile-fail/associated-types-binding-to-type-defined-in-supertrait.rs @@ -0,0 +1,53 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test equality constraints in a where clause where the type being +// equated appears in a supertrait. + +#![feature(associated_types)] + +pub trait Vehicle { + type Color; + + fn go(&self) { } +} + +pub trait Car : Vehicle { + fn honk(&self) { } +} + +/////////////////////////////////////////////////////////////////////////// + +struct Black; +struct ModelT; +impl Vehicle for ModelT { type Color = Black; } +impl Car for ModelT { } + +/////////////////////////////////////////////////////////////////////////// + +struct Blue; +struct ModelU; +impl Vehicle for ModelU { type Color = Blue; } +impl Car for ModelU { } + +/////////////////////////////////////////////////////////////////////////// + +fn black_car>(c: C) { +} + +fn blue_car>(c: C) { +} + +fn a() { black_car(ModelT); } +fn b() { blue_car(ModelT); } //~ ERROR type mismatch +fn c() { black_car(ModelU); } //~ ERROR type mismatch +fn d() { blue_car(ModelU); } + +pub fn main() { } diff --git a/src/test/run-pass/associated-types-iterator-binding.rs b/src/test/run-pass/associated-types-iterator-binding.rs new file mode 100644 index 00000000000..f8258466a7d --- /dev/null +++ b/src/test/run-pass/associated-types-iterator-binding.rs @@ -0,0 +1,27 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn pairwise_sub>(mut t: T) -> int { + let mut result = 0; + loop { + let front = t.next(); + let back = t.next_back(); + match (front, back) { + (Some(f), Some(b)) => { result += b - f; } + _ => { return result; } + } + } +} + +fn main() { + let v = vec!(1, 2, 3, 4, 5, 6); + let r =pairwise_sub(v.into_iter()); + assert_eq!(r, 9); +} From 7ee58632023c4941408264eeef34a68277773408 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 5 Jan 2015 05:37:11 -0500 Subject: [PATCH 5/7] Minor code formatting cleanups. --- src/librustc_typeck/collect.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 6f5eccfa198..bbafcdae1bb 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -160,7 +160,9 @@ impl<'a, 'tcx> AstConv<'tcx> for CollectCtxt<'a, 'tcx> { } match self.tcx.map.find(id.node) { - Some(ast_map::NodeItem(item)) => ty_of_item(self, &*item), + Some(ast_map::NodeItem(item)) => { + ty_of_item(self, &*item) + } Some(ast_map::NodeForeignItem(foreign_item)) => { let abi = self.tcx.map.get_foreign_abi(id.node); ty_of_foreign_item(self, &*foreign_item, abi) @@ -819,8 +821,8 @@ fn get_trait_def<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, } fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, - it: &ast::Item) - -> Rc> + it: &ast::Item) + -> Rc> { let def_id = local_def(it.id); let tcx = ccx.tcx; From 57aaa9bf87a233753d34fb19e223ed82b42f95a3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 5 Jan 2015 06:08:03 -0500 Subject: [PATCH 6/7] Make supertrait references work in object types too. --- src/librustc_typeck/astconv.rs | 56 +++++++++++++++---- ...ociated-type-doubleendediterator-object.rs | 27 +++++++++ 2 files changed, 71 insertions(+), 12 deletions(-) create mode 100644 src/test/run-pass/associated-type-doubleendediterator-object.rs diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index e216338b1e3..c616f4feaff 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -627,7 +627,8 @@ fn ast_path_to_trait_ref<'a,'tcx>( } Some(ref mut v) => { for binding in assoc_bindings.iter() { - match ast_type_binding_to_projection_predicate(this, trait_ref.clone(), binding) { + match ast_type_binding_to_projection_predicate(this, trait_ref.clone(), + self_ty, binding) { Ok(pp) => { v.push(pp); } Err(ErrorReported) => { } } @@ -640,10 +641,13 @@ fn ast_path_to_trait_ref<'a,'tcx>( fn ast_type_binding_to_projection_predicate<'tcx>( this: &AstConv<'tcx>, - trait_ref: Rc>, + mut trait_ref: Rc>, + self_ty: Option>, binding: &ConvertedBinding<'tcx>) -> Result, ErrorReported> { + let tcx = this.tcx(); + // Given something like `U : SomeTrait`, we want to produce a // predicate like `::T = X`. This is somewhat // subtle in the event that `T` is defined in a supertrait of @@ -671,39 +675,67 @@ fn ast_type_binding_to_projection_predicate<'tcx>( }); } - // Otherwise, we have to walk through the supertraits to find those that do. - let mut candidates: Vec<_> = - traits::supertraits(this.tcx(), trait_ref.to_poly_trait_ref()) + // Otherwise, we have to walk through the supertraits to find + // those that do. This is complicated by the fact that, for an + // object type, the `Self` type is not present in the + // substitutions (after all, it's being constructed right now), + // but the `supertraits` iterator really wants one. To handle + // this, we currently insert a dummy type and then remove it + // later. Yuck. + + let dummy_self_ty = ty::mk_infer(tcx, ty::FreshTy(0)); + if self_ty.is_none() { // if converting for an object type + let mut dummy_substs = trait_ref.substs.clone(); + assert!(dummy_substs.self_ty().is_none()); + dummy_substs.types.push(SelfSpace, dummy_self_ty); + trait_ref = Rc::new(ty::TraitRef::new(trait_ref.def_id, + tcx.mk_substs(dummy_substs))); + } + + let mut candidates: Vec = + traits::supertraits(tcx, trait_ref.to_poly_trait_ref()) .filter(|r| trait_defines_associated_type_named(this, r.def_id(), binding.item_name)) .collect(); + // If converting for an object type, then remove the dummy-ty from `Self` now. + // Yuckety yuck. + if self_ty.is_none() { + for candidate in candidates.iter_mut() { + let mut dummy_substs = candidate.0.substs.clone(); + assert!(dummy_substs.self_ty() == Some(dummy_self_ty)); + dummy_substs.types.pop(SelfSpace); + *candidate = ty::Binder(Rc::new(ty::TraitRef::new(candidate.def_id(), + tcx.mk_substs(dummy_substs)))); + } + } + if candidates.len() > 1 { - this.tcx().sess.span_err( + tcx.sess.span_err( binding.span, format!("ambiguous associated type: `{}` defined in multiple supertraits `{}`", token::get_name(binding.item_name), - candidates.user_string(this.tcx())).as_slice()); + candidates.user_string(tcx)).as_slice()); return Err(ErrorReported); } let candidate = match candidates.pop() { Some(c) => c, None => { - this.tcx().sess.span_err( + tcx.sess.span_err( binding.span, format!("no associated type `{}` defined in `{}`", token::get_name(binding.item_name), - trait_ref.user_string(this.tcx())).as_slice()); + trait_ref.user_string(tcx)).as_slice()); return Err(ErrorReported); } }; - if ty::binds_late_bound_regions(this.tcx(), &candidate) { - this.tcx().sess.span_err( + if ty::binds_late_bound_regions(tcx, &candidate) { + tcx.sess.span_err( binding.span, format!("associated type `{}` defined in higher-ranked supertrait `{}`", token::get_name(binding.item_name), - candidate.user_string(this.tcx())).as_slice()); + candidate.user_string(tcx)).as_slice()); return Err(ErrorReported); } diff --git a/src/test/run-pass/associated-type-doubleendediterator-object.rs b/src/test/run-pass/associated-type-doubleendediterator-object.rs new file mode 100644 index 00000000000..429027cbf30 --- /dev/null +++ b/src/test/run-pass/associated-type-doubleendediterator-object.rs @@ -0,0 +1,27 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn pairwise_sub(mut t: Box>) -> int { + let mut result = 0; + loop { + let front = t.next(); + let back = t.next_back(); + match (front, back) { + (Some(f), Some(b)) => { result += b - f; } + _ => { return result; } + } + } +} + +fn main() { + let v = vec!(1, 2, 3, 4, 5, 6); + let r = pairwise_sub(box v.into_iter()); + assert_eq!(r, 9); +} From 928bb2be8fee3600db086cfa94775ac9110937e2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 5 Jan 2015 09:14:03 -0500 Subject: [PATCH 7/7] Improve test to include a projection, per @huonw's suggestion. --- .../associated-type-projection-from-multiple-supertraits.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs b/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs index 553e36f0e62..6555aa32027 100644 --- a/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs +++ b/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs @@ -38,4 +38,10 @@ fn dent_object(c: BoxCar) { //~^ ERROR ambiguous associated type } +fn paint(c: C, d: C::Color) { + //~^ ERROR ambiguous associated type `Color` in bounds of `C` + //~| NOTE could derive from `Vehicle` + //~| NOTE could derive from `Box` +} + pub fn main() { }