X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Flibrustc_typeck%2Fcheck%2Fmod.rs;h=819f44372979613323413ddc33d46ae50ad67b3c;hb=89c0be547e1c381317db56982757704ea597967a;hp=9486e4953f8516042bdf14e4c9423bc5246c4b58;hpb=f0b7ede78a25686875d1028251f15b915fd0e6e8;p=rust.git diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9486e4953f8..819f4437297 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -87,6 +87,7 @@ use middle::astconv_util::{check_path_args, NO_TPS, NO_REGIONS}; use middle::def; use middle::infer; +use middle::infer::type_variable; use middle::pat_util::{self, pat_id_map}; use middle::privacy::{AllPublic, LastMod}; use middle::region::{self, CodeExtent}; @@ -108,6 +109,7 @@ use util::lev_distance::lev_distance; use std::cell::{Cell, Ref, RefCell}; +use std::collections::HashSet; use std::mem::replace; use std::slice; use syntax::{self, abi, attr}; @@ -115,8 +117,9 @@ use syntax::ast::{self, DefId, Visibility}; use syntax::ast_util::{self, local_def}; use syntax::codemap::{self, Span}; +use syntax::feature_gate::emit_feature_err; use syntax::owned_slice::OwnedSlice; -use syntax::parse::token; +use syntax::parse::token::{self, InternedString}; use syntax::print::pprust; use syntax::ptr::P; use syntax::visit::{self, Visitor}; @@ -502,7 +505,7 @@ fn visit_pat(&mut self, p: &'tcx ast::Pat) { traits::VariableType(p.id)); debug!("Pattern binding {} is assigned to {} with type {:?}", - token::get_ident(path1.node), + path1.node, self.fcx.infcx().ty_to_string( self.fcx.inh.locals.borrow().get(&p.id).unwrap().clone()), var_ty); @@ -659,7 +662,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { } ast::ItemFn(..) => {} // entirely within check_item_body ast::ItemImpl(_, _, _, _, _, ref impl_items) => { - debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id); + debug!("ItemImpl {} with id {}", it.ident, it.id); match ccx.tcx.impl_trait_ref(local_def(it.id)) { Some(impl_trait_ref) => { check_impl_items_against_trait(ccx, @@ -715,7 +718,7 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { check_bare_fn(ccx, &**decl, &**body, it.id, it.span, fn_pty.ty, param_env); } ast::ItemImpl(_, _, _, _, _, ref impl_items) => { - debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id); + debug!("ItemImpl {} with id {}", it.ident, it.id); let impl_pty = ccx.tcx.lookup_item_type(ast_util::local_def(it.id)); @@ -793,14 +796,14 @@ fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, Position::ArgumentNamed(s) if s == "Self" => (), // So is `{A}` if A is a type parameter Position::ArgumentNamed(s) => match types.iter().find(|t| { - t.ident.as_str() == s + t.ident.name == s }) { Some(_) => (), None => { span_err!(ccx.tcx.sess, attr.span, E0230, "there is no type parameter \ {} on trait {}", - s, item.ident.as_str()); + s, item.ident); } }, // `{:1}` and `{}` are not to be used @@ -862,7 +865,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // This is checked by resolve tcx.sess.span_bug(impl_item.span, &format!("impl-item `{}` is not a member of `{:?}`", - token::get_name(ty_impl_item.name()), + ty_impl_item.name(), impl_trait_ref)); }); match impl_item.node { @@ -883,7 +886,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span_err!(tcx.sess, impl_item.span, E0323, "item `{}` is an associated const, \ which doesn't match its trait `{:?}`", - token::get_name(impl_const.name), + impl_const.name, impl_trait_ref) } } @@ -906,7 +909,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span_err!(tcx.sess, impl_item.span, E0324, "item `{}` is an associated method, \ which doesn't match its trait `{:?}`", - token::get_name(impl_method.name), + impl_method.name, impl_trait_ref) } } @@ -924,7 +927,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span_err!(tcx.sess, impl_item.span, E0325, "item `{}` is an associated type, \ which doesn't match its trait `{:?}`", - token::get_name(impl_type.name), + impl_type.name, impl_trait_ref) } } @@ -1006,7 +1009,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span_err!(tcx.sess, impl_span, E0046, "not all trait items implemented, missing: `{}`", missing_items.iter() - .map(::as_str) + .map(|name| name.to_string()) .collect::>().join("`, `")) } @@ -1015,9 +1018,9 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span_err!(tcx.sess, invalidator.span, E0399, "the following trait items need to be reimplemented \ as `{}` was overridden: `{}`", - invalidator.ident.as_str(), + invalidator.ident, invalidated_items.iter() - .map(::as_str) + .map(|name| name.to_string()) .collect::>().join("`, `")) } } @@ -1136,8 +1139,27 @@ fn trait_defines_associated_type_named(&self, trait_def.associated_type_names.contains(&assoc_name) } - fn ty_infer(&self, _span: Span) -> Ty<'tcx> { - self.infcx().next_ty_var() + fn ty_infer(&self, + ty_param_def: Option>, + substs: Option<&mut subst::Substs<'tcx>>, + space: Option, + span: Span) -> Ty<'tcx> { + // Grab the default doing subsitution + let default = ty_param_def.and_then(|def| { + def.default.map(|ty| type_variable::Default { + ty: ty.subst_spanned(self.tcx(), substs.as_ref().unwrap(), Some(span)), + origin_span: span, + def_id: def.default_def_id + }) + }); + + let ty_var = self.infcx().next_ty_var_with_default(default); + + // Finally we add the type variable to the substs + match substs { + None => ty_var, + Some(substs) => { substs.types.push(space.unwrap(), ty_var); ty_var } + } } fn projected_ty_from_poly_trait_ref(&self, @@ -1254,28 +1276,6 @@ pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> Ty<'tcx> { } } - /// Apply "fallbacks" to some types - /// ! gets replaced with (), unconstrained ints with i32, and unconstrained floats with f64. - pub fn default_type_parameters(&self) { - use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; - for (_, &mut ref ty) in &mut self.inh.tables.borrow_mut().node_types { - let resolved = self.infcx().resolve_type_vars_if_possible(ty); - if self.infcx().type_var_diverges(resolved) { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); - } else { - match self.infcx().type_is_unconstrained_numeric(resolved) { - UnconstrainedInt => { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32) - }, - UnconstrainedFloat => { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64) - } - Neither => { } - } - } - } - } - #[inline] pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) { debug!("write_ty({}, {:?}) in fcx {}", @@ -1709,14 +1709,260 @@ fn check_casts(&self) { } } + /// Apply "fallbacks" to some types + /// ! gets replaced with (), unconstrained ints with i32, and unconstrained floats with f64. + fn default_type_parameters(&self) { + use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; + for ty in &self.infcx().unsolved_variables() { + let resolved = self.infcx().resolve_type_vars_if_possible(ty); + if self.infcx().type_var_diverges(resolved) { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); + } else { + match self.infcx().type_is_unconstrained_numeric(resolved) { + UnconstrainedInt => { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32) + }, + UnconstrainedFloat => { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64) + } + Neither => { } + } + } + } + } + fn select_all_obligations_and_apply_defaults(&self) { - debug!("select_all_obligations_and_apply_defaults"); + if self.tcx().sess.features.borrow().default_type_parameter_fallback { + self.new_select_all_obligations_and_apply_defaults(); + } else { + self.old_select_all_obligations_and_apply_defaults(); + } + } + // Implements old type inference fallback algorithm + fn old_select_all_obligations_and_apply_defaults(&self) { self.select_obligations_where_possible(); self.default_type_parameters(); self.select_obligations_where_possible(); } + fn new_select_all_obligations_and_apply_defaults(&self) { + use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; + + // For the time being this errs on the side of being memory wasteful but provides better + // error reporting. + // let type_variables = self.infcx().type_variables.clone(); + + // There is a possibility that this algorithm will have to run an arbitrary number of times + // to terminate so we bound it by the compiler's recursion limit. + for _ in (0..self.tcx().sess.recursion_limit.get()) { + // First we try to solve all obligations, it is possible that the last iteration + // has made it possible to make more progress. + self.select_obligations_where_possible(); + + let mut conflicts = Vec::new(); + + // Collect all unsolved type, integral and floating point variables. + let unsolved_variables = self.inh.infcx.unsolved_variables(); + + // We must collect the defaults *before* we do any unification. Because we have + // directly attached defaults to the type variables any unification that occurs + // will erase defaults causing conflicting defaults to be completely ignored. + let default_map: FnvHashMap<_, _> = + unsolved_variables + .iter() + .filter_map(|t| self.infcx().default(t).map(|d| (t, d))) + .collect(); + + let mut unbound_tyvars = HashSet::new(); + + debug!("select_all_obligations_and_apply_defaults: defaults={:?}", default_map); + + // We loop over the unsolved variables, resolving them and if they are + // and unconstrainted numberic type we add them to the set of unbound + // variables. We do this so we only apply literal fallback to type + // variables without defaults. + for ty in &unsolved_variables { + let resolved = self.infcx().resolve_type_vars_if_possible(ty); + if self.infcx().type_var_diverges(resolved) { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); + } else { + match self.infcx().type_is_unconstrained_numeric(resolved) { + UnconstrainedInt | UnconstrainedFloat => { + unbound_tyvars.insert(resolved); + }, + Neither => {} + } + } + } + + // We now remove any numeric types that also have defaults, and instead insert + // the type variable with a defined fallback. + for ty in &unsolved_variables { + if let Some(_default) = default_map.get(ty) { + let resolved = self.infcx().resolve_type_vars_if_possible(ty); + + debug!("select_all_obligations_and_apply_defaults: ty: {:?} with default: {:?}", + ty, _default); + + match resolved.sty { + ty::TyInfer(ty::TyVar(_)) => { + unbound_tyvars.insert(ty); + } + + ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) => { + unbound_tyvars.insert(ty); + if unbound_tyvars.contains(resolved) { + unbound_tyvars.remove(resolved); + } + } + + _ => {} + } + } + } + + // If there are no more fallbacks to apply at this point we have applied all possible + // defaults and type inference will procede as normal. + if unbound_tyvars.is_empty() { + break; + } + + // Finally we go through each of the unbound type variables and unify them with + // the proper fallback, reporting a conflicting default error if any of the + // unifications fail. We know it must be a conflicting default because the + // variable would only be in `unbound_tyvars` and have a concrete value if + // it had been solved by previously applying a default. + + // We wrap this in a transaction for error reporting, if we detect a conflict + // we will rollback the inference context to its prior state so we can probe + // for conflicts and correctly report them. + + + let _ = self.infcx().commit_if_ok(|_: &infer::CombinedSnapshot| { + for ty in &unbound_tyvars { + if self.infcx().type_var_diverges(ty) { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); + } else { + match self.infcx().type_is_unconstrained_numeric(ty) { + UnconstrainedInt => { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32) + }, + UnconstrainedFloat => { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64) + } + Neither => { + if let Some(default) = default_map.get(ty) { + let default = default.clone(); + match infer::mk_eqty(self.infcx(), false, + infer::Misc(default.origin_span), + ty, default.ty) { + Ok(()) => {} + Err(_) => { + conflicts.push((*ty, default)); + } + } + } + } + } + } + } + + // If there are conflicts we rollback, otherwise commit + if conflicts.len() > 0 { + Err(()) + } else { + Ok(()) + } + }); + + if conflicts.len() > 0 { + // Loop through each conflicting default, figuring out the default that caused + // a unification failure and then report an error for each. + for (conflict, default) in conflicts { + let conflicting_default = + self.find_conflicting_default(&unbound_tyvars, &default_map, conflict) + .unwrap_or(type_variable::Default { + ty: self.infcx().next_ty_var(), + origin_span: codemap::DUMMY_SP, + def_id: local_def(0) // what do I put here? + }); + + // This is to ensure that we elimnate any non-determinism from the error + // reporting by fixing an order, it doesn't matter what order we choose + // just that it is consistent. + let (first_default, second_default) = + if default.def_id < conflicting_default.def_id { + (default, conflicting_default) + } else { + (conflicting_default, default) + }; + + + self.infcx().report_conflicting_default_types( + first_default.origin_span, + first_default, + second_default) + } + } + } + + self.select_obligations_where_possible(); + } + + // For use in error handling related to default type parameter fallback. We explicitly + // apply the default that caused conflict first to a local version of the type variable + // table then apply defaults until we find a conflict. That default must be the one + // that caused conflict earlier. + fn find_conflicting_default(&self, + unbound_vars: &HashSet>, + default_map: &FnvHashMap<&Ty<'tcx>, type_variable::Default<'tcx>>, + conflict: Ty<'tcx>) + -> Option> { + use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; + + // Ensure that we apply the conflicting default first + let mut unbound_tyvars = Vec::with_capacity(unbound_vars.len() + 1); + unbound_tyvars.push(conflict); + unbound_tyvars.extend(unbound_vars.iter()); + + let mut result = None; + // We run the same code as above applying defaults in order, this time when + // we find the conflict we just return it for error reporting above. + + // We also run this inside snapshot that never commits so we can do error + // reporting for more then one conflict. + for ty in &unbound_tyvars { + if self.infcx().type_var_diverges(ty) { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); + } else { + match self.infcx().type_is_unconstrained_numeric(ty) { + UnconstrainedInt => { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32) + }, + UnconstrainedFloat => { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64) + }, + Neither => { + if let Some(default) = default_map.get(ty) { + let default = default.clone(); + match infer::mk_eqty(self.infcx(), false, + infer::Misc(default.origin_span), + ty, default.ty) { + Ok(()) => {} + Err(_) => { + result = Some(default); + } + } + } + } + } + } + } + + return result; + } + fn select_all_obligations_or_error(&self) { debug!("select_all_obligations_or_error"); @@ -1725,6 +1971,7 @@ fn select_all_obligations_or_error(&self) { assert!(self.inh.deferred_call_resolutions.borrow().is_empty()); self.select_all_obligations_and_apply_defaults(); + let mut fulfillment_cx = self.inh.infcx.fulfillment_cx.borrow_mut(); match fulfillment_cx.select_all_or_error(self.infcx()) { Ok(()) => { } @@ -2243,7 +2490,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // The special-cased logic below has three functions: // 1. Provide as good of an expected type as possible. let expected = expected_arg_tys.get(i).map(|&ty| { - Expectation::rvalue_hint(ty) + Expectation::rvalue_hint(fcx.tcx(), ty) }); check_expr_with_unifier(fcx, &**arg, @@ -2420,14 +2667,18 @@ pub fn impl_self_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let tcx = fcx.tcx(); let ity = tcx.lookup_item_type(did); - let (n_tps, rps, raw_ty) = - (ity.generics.types.len(subst::TypeSpace), + let (tps, rps, raw_ty) = + (ity.generics.types.get_slice(subst::TypeSpace), ity.generics.regions.get_slice(subst::TypeSpace), ity.ty); + debug!("impl_self_ty: tps={:?} rps={:?} raw_ty={:?}", tps, rps, raw_ty); + let rps = fcx.inh.infcx.region_vars_for_defs(span, rps); - let tps = fcx.inh.infcx.next_ty_vars(n_tps); - let substs = subst::Substs::new_type(tps, rps); + let mut substs = subst::Substs::new( + VecPerParamSpace::empty(), + VecPerParamSpace::new(rps, Vec::new(), Vec::new())); + fcx.inh.infcx.type_vars_for_defs(span, ParamSpace::TypeSpace, &mut substs, tps); let substd_ty = fcx.instantiate_type_scheme(span, &substs, &raw_ty); TypeAndSubsts { substs: substs, ty: substd_ty } @@ -2650,7 +2901,7 @@ fn check_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, field.span, |actual| { format!("attempted to take value of method `{}` on type \ - `{}`", token::get_ident(field.node), actual) + `{}`", field.node, actual) }, expr_t, None); @@ -2664,7 +2915,7 @@ fn check_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, format!("attempted access of field `{}` on \ type `{}`, but no field with that \ name was found", - token::get_ident(field.node), + field.node, actual) }, expr_t, None); @@ -2680,9 +2931,8 @@ fn check_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, fn suggest_field_names<'tcx>(id : DefId, field : &ast::SpannedIdent, tcx : &ty::ctxt<'tcx>, - skip : Vec<&str>) { - let ident = token::get_ident(field.node); - let name = &ident; + skip : Vec) { + let name = field.node.name.as_str(); // only find fits with at least one matching letter let mut best_dist = name.len(); let fields = tcx.lookup_struct_fields(id); @@ -2690,14 +2940,14 @@ fn suggest_field_names<'tcx>(id : DefId, for elem in &fields { let n = elem.name.as_str(); // ignore already set fields - if skip.iter().any(|&x| x == n) { + if skip.iter().any(|x| *x == n) { continue; } // ignore private fields from non-local crates if id.krate != ast::LOCAL_CRATE && elem.vis != Visibility::Public { continue; } - let dist = lev_distance(n, name); + let dist = lev_distance(&n, &name); if dist < best_dist { best = Some(n); best_dist = dist; @@ -2810,12 +3060,12 @@ fn check_struct_or_variant_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, class_id); format!("struct variant `{}::{}` has no field named `{}`", actual, variant_type.name.as_str(), - token::get_ident(field.ident.node)) + field.ident.node) } None => { format!("structure `{}` has no field named `{}`", actual, - token::get_ident(field.ident.node)) + field.ident.node) } }, struct_ty, @@ -2832,7 +3082,7 @@ fn check_struct_or_variant_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some((_, true)) => { span_err!(fcx.tcx().sess, field.ident.span, E0062, "field `{}` specified more than once", - token::get_ident(field.ident.node)); + field.ident.node); error_happened = true; } Some((field_id, false)) => { @@ -2866,7 +3116,7 @@ fn check_struct_or_variant_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let (_, seen) = *class_field_map.get(&name).unwrap(); if !seen { missing_fields.push( - format!("`{}`", &token::get_name(name))) + format!("`{}`", name)) } } @@ -3017,7 +3267,7 @@ fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, match unop { ast::UnUniq => match ty.sty { ty::TyBox(ty) => { - Expectation::rvalue_hint(ty) + Expectation::rvalue_hint(tcx, ty) } _ => { NoExpectation @@ -3094,7 +3344,7 @@ fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, // the last field of a struct can be unsized. ExpectHasType(mt.ty) } else { - Expectation::rvalue_hint(mt.ty) + Expectation::rvalue_hint(tcx, mt.ty) } } _ => NoExpectation @@ -3218,7 +3468,7 @@ fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, let tcx = fcx.tcx(); if !tcx.expr_is_lval(&**lhs) { span_err!(tcx.sess, expr.span, E0070, - "illegal left-hand side expression"); + "invalid left-hand side expression"); } let lhs_ty = fcx.expr_ty(&**lhs); @@ -3731,8 +3981,8 @@ impl<'tcx> Expectation<'tcx> { /// which still is useful, because it informs integer literals and the like. /// See the test case `test/run-pass/coerce-expect-unsized.rs` and #20169 /// for examples of where this comes up,. - fn rvalue_hint(ty: Ty<'tcx>) -> Expectation<'tcx> { - match ty.sty { + fn rvalue_hint(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> { + match tcx.struct_tail(ty).sty { ty::TySlice(_) | ty::TyTrait(..) => { ExpectRvalueLikeUnsized(ty) } @@ -4009,9 +4259,7 @@ fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// Checks whether a type can be represented in memory. In particular, it /// identifies types that contain themselves without indirection through a -/// pointer, which would mean their size is unbounded. This is different from -/// the question of whether a type can be instantiated. See the definition of -/// `check_instantiable`. +/// pointer, which would mean their size is unbounded. pub fn check_representable(tcx: &ty::ctxt, sp: Span, item_id: ast::NodeId, @@ -4025,10 +4273,8 @@ pub fn check_representable(tcx: &ty::ctxt, // caught by case 1. match rty.is_representable(tcx, sp) { ty::SelfRecursive => { - span_err!(tcx.sess, sp, E0072, - "illegal recursive {} type; \ - wrap the inner value in a box to make it representable", - designation); + span_err!(tcx.sess, sp, E0072, "invalid recursive {} type", designation); + tcx.sess.fileline_help(sp, "wrap the inner value in a box to make it representable"); return false } ty::Representable | ty::ContainsRecursive => (), @@ -4036,31 +4282,19 @@ pub fn check_representable(tcx: &ty::ctxt, return true } -/// Checks whether a type can be created without an instance of itself. -/// This is similar but different from the question of whether a type -/// can be represented. For example, the following type: -/// -/// enum foo { None, Some(foo) } -/// -/// is instantiable but is not representable. Similarly, the type -/// -/// enum foo { Some(@foo) } -/// -/// is representable, but not instantiable. +/// Checks whether a type can be constructed at runtime without +/// an existing instance of that type. pub fn check_instantiable(tcx: &ty::ctxt, sp: Span, - item_id: ast::NodeId) - -> bool { + item_id: ast::NodeId) { let item_ty = tcx.node_id_to_type(item_id); - if !item_ty.is_instantiable(tcx) { - span_err!(tcx.sess, sp, E0073, - "this type cannot be instantiated without an \ - instance of itself"); - fileline_help!(tcx.sess, sp, "consider using `Option<{:?}>`", - item_ty); - false - } else { - true + if !item_ty.is_instantiable(tcx) && + !tcx.sess.features.borrow().static_recursion { + emit_feature_err(&tcx.sess.parse_sess.span_diagnostic, + "static_recursion", + sp, + "this type cannot be instantiated at runtime \ + without an instance of itself"); } } @@ -4199,11 +4433,6 @@ fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, do_check(ccx, vs, id, hint); check_representable(ccx.tcx, sp, id, "enum"); - - // Check that it is possible to instantiate this enum: - // - // This *sounds* like the same that as representable, but it's - // not. See def'n of `check_instantiable()` for details. check_instantiable(ccx.tcx, sp, id); } @@ -4452,7 +4681,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // variables. If the user provided some types, we may still need // to add defaults. If the user provided *too many* types, that's // a problem. - for &space in &ParamSpace::all() { + for &space in &[subst::SelfSpace, subst::TypeSpace, subst::FnSpace] { adjust_type_parameters(fcx, span, space, type_defs, require_type_space, &mut substs); assert_eq!(substs.types.len(space), type_defs.len(space)); @@ -4665,7 +4894,8 @@ fn adjust_type_parameters<'a, 'tcx>( // Nothing specified at all: supply inference variables for // everything. if provided_len == 0 && !(require_type_space && space == subst::TypeSpace) { - substs.types.replace(space, fcx.infcx().next_ty_vars(desired.len())); + substs.types.replace(space, Vec::new()); + fcx.infcx().type_vars_for_defs(span, space, substs, &desired[..]); return; } @@ -4826,7 +5056,7 @@ pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, if !*b { span_err!(ccx.tcx.sess, span, E0091, "type parameter `{}` is unused", - token::get_ident(tps[i].ident)); + tps[i].ident); } } } @@ -4840,7 +5070,7 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> { } let tcx = ccx.tcx; - let name = token::get_ident(it.ident); + let name = it.ident.name.as_str(); let (n_tps, inputs, output) = if name.starts_with("atomic_") { let split : Vec<&str> = name.split('_').collect(); assert!(split.len() >= 2, "Atomic intrinsic not correct format");