rustc: use partially resolved definitions to replace the T::A hack.

This commit is contained in:
Eduard Burtescu 2015-02-05 13:20:48 +02:00
parent 5809f8ae74
commit 0f49254b31
16 changed files with 383 additions and 382 deletions

View File

@ -17,29 +17,47 @@
use middle::def;
use middle::ty::{self, Ty};
use syntax::ast;
use syntax::codemap::Span;
use util::ppaux::Repr;
pub const NO_REGIONS: uint = 1;
pub const NO_TPS: uint = 2;
pub fn check_path_args(tcx: &ty::ctxt,
path: &ast::Path,
span: Span,
segments: &[ast::PathSegment],
flags: uint) {
if (flags & NO_TPS) != 0 {
if path.segments.iter().any(|s| s.parameters.has_types()) {
span_err!(tcx.sess, path.span, E0109,
if segments.iter().any(|s| s.parameters.has_types()) {
span_err!(tcx.sess, span, E0109,
"type parameters are not allowed on this type");
}
}
if (flags & NO_REGIONS) != 0 {
if path.segments.iter().any(|s| s.parameters.has_lifetimes()) {
span_err!(tcx.sess, path.span, E0110,
if segments.iter().any(|s| s.parameters.has_lifetimes()) {
span_err!(tcx.sess, span, E0110,
"lifetime parameters are not allowed on this type");
}
}
}
pub fn prim_ty_to_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
span: Span,
segments: &[ast::PathSegment],
nty: ast::PrimTy)
-> Ty<'tcx> {
check_path_args(tcx, span, segments, NO_TPS | NO_REGIONS);
match nty {
ast::TyBool => tcx.types.bool,
ast::TyChar => tcx.types.char,
ast::TyInt(it) => ty::mk_mach_int(tcx, it),
ast::TyUint(uit) => ty::mk_mach_uint(tcx, uit),
ast::TyFloat(ft) => ty::mk_mach_float(tcx, ft),
ast::TyStr => ty::mk_str(tcx)
}
}
pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty)
-> Option<Ty<'tcx>> {
if let ast::TyPath(ref path) = ast_ty.node {
@ -51,15 +69,7 @@ pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty)
Some(&d) => d
};
if let def::DefPrimTy(nty) = def {
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
Some(match nty {
ast::TyBool => tcx.types.bool,
ast::TyChar => tcx.types.char,
ast::TyInt(it) => ty::mk_mach_int(tcx, it),
ast::TyUint(uit) => ty::mk_mach_uint(tcx, uit),
ast::TyFloat(ft) => ty::mk_mach_float(tcx, ft),
ast::TyStr => ty::mk_str(tcx)
})
Some(prim_ty_to_ty(tcx, path.span, &path.segments[], nty))
} else {
None
}

View File

@ -444,10 +444,6 @@ impl tr for def::Def {
def::DefTy(did, is_enum) => def::DefTy(did.tr(dcx), is_enum),
def::DefAssociatedTy(trait_did, did) =>
def::DefAssociatedTy(trait_did.tr(dcx), did.tr(dcx)),
def::DefAssociatedPath(def::TyParamProvenance::FromSelf(did), ident) =>
def::DefAssociatedPath(def::TyParamProvenance::FromSelf(did.tr(dcx)), ident),
def::DefAssociatedPath(def::TyParamProvenance::FromParam(did), ident) =>
def::DefAssociatedPath(def::TyParamProvenance::FromParam(did.tr(dcx)), ident),
def::DefPrimTy(p) => def::DefPrimTy(p),
def::DefTyParam(s, index, def_id, n) => def::DefTyParam(s, index, def_id.tr(dcx), n),
def::DefUse(did) => def::DefUse(did.tr(dcx)),

View File

@ -33,11 +33,6 @@ pub enum Def {
DefVariant(ast::DefId /* enum */, ast::DefId /* variant */, bool /* is_structure */),
DefTy(ast::DefId, bool /* is_enum */),
DefAssociatedTy(ast::DefId /* trait */, ast::DefId),
// A partially resolved path to an associated type `T::U` where `T` is a concrete
// type (indicated by the DefId) which implements a trait which has an associated
// type `U` (indicated by the Ident).
// FIXME(#20301) -- should use Name
DefAssociatedPath(TyParamProvenance, ast::Ident),
DefTrait(ast::DefId),
DefPrimTy(ast::PrimTy),
DefTyParam(ParamSpace, u32, ast::DefId, ast::Name),
@ -59,8 +54,24 @@ pub enum Def {
DefMethod(ast::DefId /* method */, Option<ast::DefId> /* trait */, MethodProvenance),
}
/// The result of resolving the prefix of a path to a type:
///
/// module::Type::AssocA::AssocB::AssocC::MethodOrAssocType
/// ^~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~
/// base_type extra_associated_types
///
/// <T as Trait>::AssocA::AssocB::AssocC::MethodOrAssocType
/// ^~~~~~~~~~~~~~ ^~~~~~~~~~~~~~
/// base_type extra_associated_types
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct PartialDef {
pub base_type: Def,
pub extra_associated_types: u32,
}
// Definition mapping
pub type DefMap = RefCell<NodeMap<Def>>;
pub type PartialDefMap = RefCell<NodeMap<PartialDef>>;
// This is the replacement export map. It maps a module to all of the exports
// within.
pub type ExportMap = NodeMap<Vec<Export>>;
@ -77,12 +88,6 @@ pub enum MethodProvenance {
FromImpl(ast::DefId),
}
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum TyParamProvenance {
FromSelf(ast::DefId),
FromParam(ast::DefId),
}
impl MethodProvenance {
pub fn map<F>(self, f: F) -> MethodProvenance where
F: FnOnce(ast::DefId) -> ast::DefId,
@ -94,15 +99,6 @@ impl MethodProvenance {
}
}
impl TyParamProvenance {
pub fn def_id(&self) -> ast::DefId {
match *self {
TyParamProvenance::FromSelf(ref did) => did.clone(),
TyParamProvenance::FromParam(ref did) => did.clone(),
}
}
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum TraitItemKind {
NonstaticMethodTraitItemKind,
@ -135,9 +131,7 @@ impl Def {
DefForeignMod(id) | DefStatic(id, _) |
DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) |
DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
DefMethod(id, _, _) | DefConst(id) |
DefAssociatedPath(TyParamProvenance::FromSelf(id), _) |
DefAssociatedPath(TyParamProvenance::FromParam(id), _) => {
DefMethod(id, _, _) | DefConst(id) => {
id
}
DefLocal(id) |

View File

@ -582,7 +582,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) |
def::DefTyParam(..) | def::DefRegion(_) |
def::DefLabel(_) | def::DefSelfTy(..) |
def::DefAssociatedTy(..) | def::DefAssociatedPath(..)=> {
def::DefAssociatedTy(..) => {
Ok(Rc::new(cmt_ {
id:id,
span:span,

View File

@ -46,7 +46,7 @@ use metadata::csearch;
use middle;
use middle::check_const;
use middle::const_eval;
use middle::def::{self, DefMap, ExportMap};
use middle::def::{self, DefMap, ExportMap, PartialDefMap};
use middle::dependency_format;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem};
use middle::lang_items::{FnOnceTraitLangItem, TyDescStructLangItem};
@ -682,6 +682,7 @@ pub struct ctxt<'tcx> {
pub sess: Session,
pub def_map: DefMap,
pub partial_def_map: PartialDefMap,
pub named_region_map: resolve_lifetime::NamedRegionMap,
@ -2423,7 +2424,8 @@ impl<'tcx> CommonTypes<'tcx> {
pub fn mk_ctxt<'tcx>(s: Session,
arenas: &'tcx CtxtArenas<'tcx>,
dm: DefMap,
def_map: DefMap,
partial_def_map: PartialDefMap,
named_region_map: resolve_lifetime::NamedRegionMap,
map: ast_map::Map<'tcx>,
freevars: RefCell<FreevarMap>,
@ -2445,7 +2447,8 @@ pub fn mk_ctxt<'tcx>(s: Session,
item_variance_map: RefCell::new(DefIdMap()),
variance_computed: Cell::new(false),
sess: s,
def_map: dm,
def_map: def_map,
partial_def_map: partial_def_map,
region_maps: region_maps,
node_types: RefCell::new(FnvHashMap()),
item_substs: RefCell::new(NodeMap()),

View File

@ -567,6 +567,7 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
let resolve::CrateMap {
def_map,
partial_def_map,
freevars,
export_map,
trait_map,
@ -607,6 +608,7 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
let ty_cx = ty::mk_ctxt(sess,
arenas,
def_map,
partial_def_map,
named_region_map,
ast_map,
freevars,

View File

@ -940,7 +940,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
is_public,
DUMMY_SP)
}
DefTy(..) | DefAssociatedTy(..) | DefAssociatedPath(..) => {
DefTy(..) | DefAssociatedTy(..) => {
debug!("(building reduced graph for external \
crate) building type {}", final_ident);

View File

@ -935,6 +935,7 @@ struct Resolver<'a, 'tcx:'a> {
primitive_type_table: PrimitiveTypeTable,
def_map: DefMap,
partial_def_map: PartialDefMap,
freevars: RefCell<FreevarMap>,
freevars_seen: RefCell<NodeMap<NodeSet>>,
export_map: ExportMap,
@ -1008,6 +1009,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
primitive_type_table: PrimitiveTypeTable::new(),
def_map: RefCell::new(NodeMap()),
partial_def_map: RefCell::new(NodeMap()),
freevars: RefCell::new(NodeMap()),
freevars_seen: RefCell::new(NodeMap()),
export_map: NodeMap(),
@ -2988,13 +2990,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
id: NodeId,
trait_path: &Path,
path_depth: usize)
-> Result<(Def, LastPrivate), ()> {
-> Result<(Def, LastPrivate, usize), ()> {
match self.resolve_path(id, trait_path, path_depth, TypeNS, true) {
Some(def @ (DefTrait(_), _)) => {
Some(def @ (DefTrait(_), _, _)) => {
debug!("(resolving trait) found trait def: {:?}", def);
Ok(def)
}
Some((def, _)) => {
Some((def, _, _)) => {
self.resolve_error(trait_path.span,
&format!("`{}` is not a trait",
self.path_names_to_string(trait_path, path_depth)));
@ -3025,8 +3027,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
&ast::WherePredicate::RegionPredicate(_) => {}
&ast::WherePredicate::EqPredicate(ref eq_pred) => {
match self.resolve_path(eq_pred.id, &eq_pred.path, 0, TypeNS, true) {
Some((def @ DefTyParam(..), last_private)) => {
self.record_def(eq_pred.id, (def, last_private));
Some(def @ (DefTyParam(..), _, _)) => {
self.record_def(eq_pred.id, def);
}
_ => {
self.resolve_error(eq_pred.path.span,
@ -3121,30 +3123,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
});
});
});
// Check that the current type is indeed a type, if we have an anonymous impl
if opt_trait_reference.is_none() {
match self_type.node {
// TyPath is the only thing that we handled in `build_reduced_graph_for_item`,
// where we created a module with the name of the type in order to implement
// an anonymous trait. In the case that the path does not resolve to an actual
// type, the result will be that the type name resolves to a module but not
// a type (shadowing any imported modules or types with this name), leading
// to weird user-visible bugs. So we ward this off here. See #15060.
TyPath(ref path) => {
match self.def_map.borrow().get(&self_type.id) {
// FIXME: should we catch other options and give more precise errors?
Some(&DefMod(_)) => {
self.resolve_error(path.span, "inherent implementations are not \
allowed for types not defined in \
the current module");
}
_ => {}
}
}
_ => { }
}
}
}
fn check_trait_item(&self, name: Name, span: Span) {
@ -3304,14 +3282,31 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// on whether the path has multiple elements in it or not.
TyPath(ref path) | TyQPath(ast::QPath { ref path, .. }) => {
if let TyQPath(_) = ty.node {
let max_assoc_types = if let TyQPath(_) = ty.node {
// Make sure the trait is valid.
self.resolve_trait_reference(ty.id, path, 1);
let _ = self.resolve_trait_reference(ty.id, path, 1);
1
} else {
path.segments.len()
};
let mut result = None;
for depth in 0..max_assoc_types {
self.with_no_errors(|this| {
result = this.resolve_path(ty.id, path, depth, TypeNS, true);
});
if result.is_some() {
break;
}
}
if let Some((DefMod(_), _, _)) = result {
// A module is not a valid type.
result = None;
}
// This is a path in the type namespace. Walk through scopes
// looking for it.
match self.resolve_path(ty.id, path, 0, TypeNS, true) {
match result {
Some(def) => {
// Write the result into the def map.
debug!("(resolving type) writing resolution for `{}` \
@ -3321,6 +3316,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
self.record_def(ty.id, def);
}
None => {
// Keep reporting some errors even if they're ignored above.
self.resolve_path(ty.id, path, 0, TypeNS, true);
let kind = match ty.node {
TyQPath(_) => "associated type",
_ => "type name"
@ -3371,7 +3369,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
pattern,
binding_mode,
"an enum variant");
self.record_def(pattern.id, (def, lp));
self.record_def(pattern.id, (def, lp, 0));
}
FoundStructOrEnumVariant(..) => {
self.resolve_error(
@ -3390,7 +3388,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
pattern,
binding_mode,
"a constant");
self.record_def(pattern.id, (def, lp));
self.record_def(pattern.id, (def, lp, 0));
}
FoundConst(..) => {
self.resolve_error(pattern.span,
@ -3407,7 +3405,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// will be able to distinguish variants from
// locals in patterns.
self.record_def(pattern.id, (def, LastMod(AllPublic)));
self.record_def(pattern.id, (def, LastMod(AllPublic), 0));
// Add the binding to the local ribs, if it
// doesn't already exist in the bindings list. (We
@ -3451,12 +3449,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
PatEnum(ref path, _) => {
// This must be an enum variant, struct or const.
match self.resolve_path(pat_id, path, 0, ValueNS, false) {
Some(def @ (DefVariant(..), _)) |
Some(def @ (DefStruct(..), _)) |
Some(def @ (DefConst(..), _)) => {
Some(def @ (DefVariant(..), _, _)) |
Some(def @ (DefStruct(..), _, _)) |
Some(def @ (DefConst(..), _, _)) => {
self.record_def(pattern.id, def);
}
Some((DefStatic(..), _)) => {
Some((DefStatic(..), _, _)) => {
self.resolve_error(path.span,
"static variables cannot be \
referenced in a pattern, \
@ -3573,40 +3571,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
path: &Path,
path_depth: usize,
namespace: Namespace,
check_ribs: bool) -> Option<(Def, LastPrivate)> {
check_ribs: bool) -> Option<(Def, LastPrivate, usize)> {
let span = path.span;
let segments = &path.segments[..path.segments.len()-path_depth];
// A special case for sugared associated type paths `T::A` where `T` is
// a type parameter and `A` is an associated type on some bound of `T`.
if namespace == TypeNS && segments.len() == 2 {
match self.resolve_identifier(segments[0].identifier,
TypeNS,
true,
span) {
Some((def, last_private)) => {
match def {
DefTyParam(_, _, did, _) => {
let def = DefAssociatedPath(TyParamProvenance::FromParam(did),
segments.last()
.unwrap().identifier);
return Some((def, last_private));
}
DefSelfTy(nid) => {
let def = DefAssociatedPath(TyParamProvenance::FromSelf(local_def(nid)),
segments.last()
.unwrap().identifier);
return Some((def, last_private));
}
_ => {}
}
}
_ => {}
}
}
if path.global {
return self.resolve_crate_relative_path(span, segments, namespace);
let def = self.resolve_crate_relative_path(span, segments, namespace);
return def.map(|(def, lp)| (def, lp, path_depth));
}
// Try to find a path to an item in a module.
@ -3628,10 +3599,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
_ => ()
}
return def;
def.map(|(def, lp)| (def, lp, path_depth))
} else {
unqualified_def.map(|(def, lp)| (def, lp, path_depth))
}
unqualified_def
}
// resolve a single identifier (used as a varref)
@ -4105,14 +4076,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ExprPath(ref path) | ExprQPath(ast::QPath { ref path, .. }) => {
if let ExprQPath(_) = expr.node {
// Make sure the trait is valid.
self.resolve_trait_reference(expr.id, path, 1);
let _ = self.resolve_trait_reference(expr.id, path, 1);
}
// This is a local path in the value namespace. Walk through
// scopes looking for it.
match self.resolve_path(expr.id, path, 0, ValueNS, true) {
// Check if struct variant
Some((DefVariant(_, _, true), _)) => {
Some((DefVariant(_, _, true), _, _)) => {
let path_name = self.path_names_to_string(path, 0);
self.resolve_error(expr.span,
&format!("`{}` is a struct variant name, but \
@ -4140,7 +4111,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let path_name = self.path_names_to_string(path, 0);
match self.with_no_errors(|this|
this.resolve_path(expr.id, path, 0, TypeNS, false)) {
Some((DefTy(struct_id, _), _))
Some((DefTy(struct_id, _), _, 0))
if self.structs.contains_key(&struct_id) => {
self.resolve_error(expr.span,
&format!("`{}` is a structure name, but \
@ -4252,7 +4223,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
Some(DlDef(def @ DefLabel(_))) => {
// Since this def is a label, it is never read.
self.record_def(expr.id, (def, LastMod(AllPublic)))
self.record_def(expr.id, (def, LastMod(AllPublic), 0))
}
Some(_) => {
self.session.span_bug(expr.span,
@ -4372,18 +4343,31 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
fn record_def(&mut self,
node_id: NodeId,
(def, lp): (Def, LastPrivate)) {
(def, lp, depth): (Def, LastPrivate, usize)) {
debug!("(recording def) recording {:?} for {}, last private {:?}",
def, node_id, lp);
assert!(match lp {LastImport{..} => false, _ => true},
"Import should only be used for `use` directives");
self.last_private.insert(node_id, lp);
if let Some(prev_def) = self.def_map.borrow_mut().insert(node_id, def) {
let span = self.ast_map.opt_span(node_id).unwrap_or(codemap::DUMMY_SP);
self.session.span_bug(span, &format!("path resolved multiple times \
({:?} before, {:?} now)",
prev_def, def));
if depth == 0 {
if let Some(prev_def) = self.def_map.borrow_mut().insert(node_id, def) {
let span = self.ast_map.opt_span(node_id).unwrap_or(codemap::DUMMY_SP);
self.session.span_bug(span, &format!("path resolved multiple times \
({:?} before, {:?} now)",
prev_def, def));
}
} else {
let def = PartialDef {
base_type: def,
extra_associated_types: (depth - 1) as u32
};
if let Some(prev_def) = self.partial_def_map.borrow_mut().insert(node_id, def) {
let span = self.ast_map.opt_span(node_id).unwrap_or(codemap::DUMMY_SP);
self.session.span_bug(span, &format!("path resolved multiple times \
({:?} before, {:?} now)",
prev_def, def));
}
}
}
@ -4474,6 +4458,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
pub struct CrateMap {
pub def_map: DefMap,
pub partial_def_map: PartialDefMap,
pub freevars: RefCell<FreevarMap>,
pub export_map: ExportMap,
pub trait_map: TraitMap,
@ -4513,6 +4498,7 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session,
CrateMap {
def_map: resolver.def_map,
partial_def_map: resolver.partial_def_map,
freevars: resolver.freevars,
export_map: resolver.export_map,
trait_map: resolver.trait_map,

View File

@ -238,7 +238,6 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
def::DefStruct(_) => Some(recorder::StructRef),
def::DefTy(..) |
def::DefAssociatedTy(..) |
def::DefAssociatedPath(..) |
def::DefTrait(_) => Some(recorder::TypeRef),
def::DefStatic(_, _) |
def::DefConst(_) |

View File

@ -210,7 +210,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
def::DefMod(..) | def::DefForeignMod(..) | def::DefTrait(..) |
def::DefTy(..) | def::DefPrimTy(..) | def::DefAssociatedTy(..) |
def::DefUse(..) | def::DefRegion(..) | def::DefLabel(..) |
def::DefTyParam(..) | def::DefSelfTy(..) | def::DefAssociatedPath(..) => {
def::DefTyParam(..) | def::DefSelfTy(..) => {
bcx.tcx().sess.span_bug(
ref_expr.span,
&format!("cannot translate def {:?} \

View File

@ -48,7 +48,7 @@
//! case but `&a` in the second. Basically, defaults that appear inside
//! an rptr (`&r.T`) use the region `r` that appears in the rptr.
use middle::astconv_util::{ast_ty_to_prim_ty, check_path_args, NO_TPS, NO_REGIONS};
use middle::astconv_util::{prim_ty_to_ty, check_path_args, NO_TPS, NO_REGIONS};
use middle::const_eval;
use middle::def;
use middle::resolve_lifetime as rl;
@ -57,13 +57,13 @@ use middle::traits;
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
use TypeAndSubsts;
use util::common::{ErrorReported, FN_OUTPUT_NAME};
use util::nodemap::DefIdMap;
use util::ppaux::{self, Repr, UserString};
use std::rc::Rc;
use std::iter::{repeat, AdditiveIterator};
use std::rc::Rc;
use std::slice;
use syntax::{abi, ast, ast_util};
use syntax::codemap::Span;
use syntax::parse::token;
@ -245,8 +245,9 @@ pub fn opt_ast_region_to_region<'tcx>(
pub fn ast_path_substs_for_ty<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
decl_generics: &ty::Generics<'tcx>,
path: &ast::Path)
item_segment: &ast::PathSegment)
-> Substs<'tcx>
{
let tcx = this.tcx();
@ -262,12 +263,12 @@ pub fn ast_path_substs_for_ty<'tcx>(
assert!(decl_generics.regions.all(|d| d.space == TypeSpace));
assert!(decl_generics.types.all(|d| d.space != FnSpace));
let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
let (regions, types, assoc_bindings) = match item_segment.parameters {
ast::AngleBracketedParameters(ref data) => {
convert_angle_bracketed_parameters(this, rscope, path.span, decl_generics, data)
}
ast::ParenthesizedParameters(ref data) => {
span_err!(tcx.sess, path.span, E0214,
span_err!(tcx.sess, span, E0214,
"parenthesized parameters may only be used with a trait");
convert_parenthesized_parameters(this, rscope, path.span, decl_generics, data)
}
@ -276,7 +277,7 @@ pub fn ast_path_substs_for_ty<'tcx>(
prohibit_projections(this.tcx(), &assoc_bindings);
create_substs_for_ast_path(this,
path.span,
span,
decl_generics,
None,
types,
@ -625,8 +626,9 @@ pub fn instantiate_trait_ref<'tcx>(
fn object_path_to_poly_trait_ref<'a,'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
trait_def_id: ast::DefId,
path: &ast::Path,
trait_segment: &ast::PathSegment,
mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
-> ty::PolyTraitRef<'tcx>
{
@ -637,10 +639,10 @@ fn object_path_to_poly_trait_ref<'a,'tcx>(
let mut tmp = Vec::new();
let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
&shifted_rscope,
path.span,
span,
trait_def_id,
None,
path.segments.last().unwrap(),
trait_segment,
Some(&mut tmp)));
projections.extend(tmp.into_iter().map(ty::Binder));
trait_ref
@ -824,78 +826,28 @@ fn ast_type_binding_to_projection_predicate<'tcx>(
})
}
pub fn ast_path_to_ty<'tcx>(
fn ast_path_to_ty<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
did: ast::DefId,
path: &ast::Path)
-> TypeAndSubsts<'tcx>
item_segment: &ast::PathSegment)
-> Ty<'tcx>
{
let tcx = this.tcx();
let ty::TypeScheme {
generics,
ty: decl_ty
} = this.get_item_type_scheme(did);
let substs = ast_path_substs_for_ty(this,
rscope,
&generics,
path);
let ty = decl_ty.subst(tcx, &substs);
TypeAndSubsts { substs: substs, ty: ty }
}
let substs = ast_path_substs_for_ty(this, rscope, span, &generics, item_segment);
/// 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>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
ast_ty: &ast::Ty)
-> Option<Ty<'tcx>> {
match ast_ty_to_prim_ty(this.tcx(), ast_ty) {
Some(typ) => return Some(typ),
None => {}
// FIXME(#12938): This is a hack until we have full support for DST.
if Some(did) == this.tcx().lang_items.owned_box() {
assert_eq!(substs.types.len(TypeSpace), 1);
return ty::mk_uniq(this.tcx(), *substs.types.get(TypeSpace, 0));
}
match ast_ty.node {
ast::TyPath(ref path) => {
let a_def = match this.tcx().def_map.borrow().get(&ast_ty.id) {
None => {
this.tcx()
.sess
.span_bug(ast_ty.span,
&format!("unbound path {}",
path.repr(this.tcx())))
}
Some(&d) => d
};
// FIXME(#12938): This is a hack until we have full support for
// DST.
match a_def {
def::DefTy(did, _) |
def::DefStruct(did) if Some(did) == this.tcx().lang_items.owned_box() => {
let ty = ast_path_to_ty(this, rscope, did, path).ty;
match ty.sty {
ty::ty_struct(struct_def_id, ref substs) => {
assert_eq!(struct_def_id, did);
assert_eq!(substs.types.len(TypeSpace), 1);
let referent_ty = *substs.types.get(TypeSpace, 0);
Some(ty::mk_uniq(this.tcx(), referent_ty))
}
_ => {
this.tcx().sess.span_bug(
path.span,
&format!("converting `Box` to `{}`",
ty.repr(this.tcx())));
}
}
}
_ => None
}
}
_ => None
}
decl_ty.subst(this.tcx(), &substs)
}
type TraitAndProjections<'tcx> = (ty::PolyTraitRef<'tcx>, Vec<ty::PolyProjectionPredicate<'tcx>>);
@ -919,13 +871,15 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>,
match ty.node {
ast::TyPath(ref path) => {
match this.tcx().def_map.borrow().get(&ty.id) {
Some(&def::DefTrait(trait_def_id)) => {
let def = this.tcx().def_map.borrow().get(&ty.id).cloned();
match def {
Some(def::DefTrait(trait_def_id)) => {
let mut projection_bounds = Vec::new();
let trait_ref = object_path_to_poly_trait_ref(this,
rscope,
path.span,
trait_def_id,
path,
path.segments.last().unwrap(),
&mut projection_bounds);
Ok((trait_ref, projection_bounds))
}
@ -989,21 +943,35 @@ fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>,
}
fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
ast_ty: &ast::Ty,
provenance: def::TyParamProvenance,
assoc_name: ast::Name)
-> Ty<'tcx>
span: Span,
ty: Ty<'tcx>,
ty_path_def: def::Def,
item_segment: &ast::PathSegment)
-> (Ty<'tcx>, def::Def)
{
let tcx = this.tcx();
let ty_param_def_id = provenance.def_id();
check_path_args(tcx, span, slice::ref_slice(item_segment),
NO_TPS | NO_REGIONS);
let assoc_name = item_segment.identifier.name;
let ty_param_node_id = if let ty::ty_param(_) = ty.sty {
ty_path_def.local_node_id()
} else {
span_err!(tcx.sess, span, E0223,
"ambiguous associated type; specify the type using the syntax \
`<{} as Trait>::{}`",
ty.user_string(tcx), token::get_name(assoc_name));
return (tcx.types.err, ty_path_def);
};
let mut suitable_bounds: Vec<_>;
let ty_param_name: ast::Name;
{ // contain scope of refcell:
let ty_param_defs = tcx.ty_param_defs.borrow();
let ty_param_def = &ty_param_defs[ty_param_def_id.node];
let ty_param_def = &ty_param_defs[ty_param_node_id];
ty_param_name = ty_param_def.name;
// FIXME(#20300) -- search where clauses, not bounds
suitable_bounds =
traits::transitive_bounds(tcx, &ty_param_def.bounds.trait_bounds)
@ -1012,21 +980,21 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
}
if suitable_bounds.len() == 0 {
span_err!(tcx.sess, ast_ty.span, E0220,
span_err!(tcx.sess, span, E0220,
"associated type `{}` not found for type parameter `{}`",
token::get_name(assoc_name),
token::get_name(ty_param_name));
return this.tcx().types.err;
return (this.tcx().types.err, ty_path_def);
}
if suitable_bounds.len() > 1 {
span_err!(tcx.sess, ast_ty.span, E0221,
span_err!(tcx.sess, span, E0221,
"ambiguous associated type `{}` in bounds of `{}`",
token::get_name(assoc_name),
token::get_name(ty_param_name));
for suitable_bound in &suitable_bounds {
span_note!(this.tcx().sess, ast_ty.span,
span_note!(this.tcx().sess, span,
"associated type `{}` could derive from `{}`",
token::get_name(ty_param_name),
suitable_bound.user_string(this.tcx()));
@ -1034,7 +1002,32 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
}
let suitable_bound = suitable_bounds.pop().unwrap().clone();
return this.projected_ty_from_poly_trait_ref(ast_ty.span, suitable_bound, assoc_name);
let trait_did = suitable_bound.0.def_id;
let ty = this.projected_ty_from_poly_trait_ref(span, suitable_bound, assoc_name);
let item_did = if trait_did.krate == ast::LOCAL_CRATE {
// `ty::trait_items` used below requires information generated
// by type collection, which may be in progress at this point.
match this.tcx().map.expect_item(trait_did.node).node {
ast::ItemTrait(_, _, _, ref trait_items) => {
trait_items.iter().filter_map(|i| {
if let ast::TypeTraitItem(ref assoc) = *i {
if assoc.ty_param.ident.name == assoc_name {
return Some(ast_util::local_def(assoc.ty_param.id));
}
}
None
}).next().expect("missing associated type")
}
_ => unreachable!()
}
} else {
let trait_items = ty::trait_items(this.tcx(), trait_did);
let item = trait_items.iter().find(|i| i.name() == assoc_name);
item.expect("missing associated type").def_id()
};
(ty, def::DefAssociatedTy(trait_did, item_did))
}
fn trait_defines_associated_type_named(this: &AstConv,
@ -1058,6 +1051,9 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
{
let tcx = this.tcx();
check_path_args(tcx, span, slice::ref_slice(item_segment),
NO_TPS | NO_REGIONS);
let self_ty = if let Some(ty) = opt_self_ty {
ast_ty_to_ty(this, rscope, ty)
} else {
@ -1081,9 +1077,6 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx));
// `<T as Trait>::U<V>` shouldn't parse right now.
assert!(item_segment.parameters.is_empty());
this.projected_ty(span, trait_ref, item_segment.identifier.name)
}
@ -1146,164 +1139,184 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
ast_ty_to_ty_cache.insert(ast_ty.id, ty::atttce_unresolved);
drop(ast_ty_to_ty_cache);
let typ = ast_ty_to_builtin_ty(this, rscope, ast_ty).unwrap_or_else(|| {
match ast_ty.node {
ast::TyVec(ref ty) => {
ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), None)
}
ast::TyObjectSum(ref ty, ref bounds) => {
match ast_ty_to_trait_ref(this, rscope, &**ty, &bounds[..]) {
Ok((trait_ref, projection_bounds)) => {
trait_ref_to_object_type(this,
rscope,
ast_ty.span,
trait_ref,
projection_bounds,
&bounds[..])
}
Err(ErrorReported) => {
this.tcx().types.err
}
let typ = match ast_ty.node {
ast::TyVec(ref ty) => {
ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), None)
}
ast::TyObjectSum(ref ty, ref bounds) => {
match ast_ty_to_trait_ref(this, rscope, &**ty, bounds) {
Ok((trait_ref, projection_bounds)) => {
trait_ref_to_object_type(this,
rscope,
ast_ty.span,
trait_ref,
projection_bounds,
bounds)
}
}
ast::TyPtr(ref mt) => {
ty::mk_ptr(tcx, ty::mt {
ty: ast_ty_to_ty(this, rscope, &*mt.ty),
mutbl: mt.mutbl
})
}
ast::TyRptr(ref region, ref mt) => {
let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region);
debug!("ty_rptr r={}", r.repr(this.tcx()));
let rscope1 =
&ObjectLifetimeDefaultRscope::new(
rscope,
Some(ty::ObjectLifetimeDefault::Specific(r)));
let t = ast_ty_to_ty(this, rscope1, &*mt.ty);
ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl})
}
ast::TyTup(ref fields) => {
let flds = fields.iter()
.map(|t| ast_ty_to_ty(this, rscope, &**t))
.collect();
ty::mk_tup(tcx, flds)
}
ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ),
ast::TyBareFn(ref bf) => {
if bf.decl.variadic && bf.abi != abi::C {
span_err!(tcx.sess, ast_ty.span, E0222,
"variadic function must have C calling convention");
Err(ErrorReported) => {
this.tcx().types.err
}
let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl);
ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(bare_fn))
}
ast::TyPolyTraitRef(ref bounds) => {
conv_ty_poly_trait_ref(this, rscope, ast_ty.span, &bounds[..])
}
ast::TyPath(ref path) | ast::TyQPath(ast::QPath { ref path, .. }) => {
let a_def = match tcx.def_map.borrow().get(&ast_ty.id) {
None => {
tcx.sess
.span_bug(ast_ty.span,
&format!("unbound path {}",
ast_ty.repr(tcx)))
}
Some(&d) => d
};
match a_def {
def::DefTrait(trait_def_id) => {
// N.B. this case overlaps somewhat with
// TyObjectSum, see that fn for details
let mut projection_bounds = Vec::new();
let trait_ref = object_path_to_poly_trait_ref(this,
rscope,
trait_def_id,
path,
&mut projection_bounds);
trait_ref_to_object_type(this, rscope, ast_ty.span,
trait_ref, projection_bounds, &[])
}
def::DefTy(did, _) | def::DefStruct(did) => {
ast_path_to_ty(this, rscope, did, path).ty
}
def::DefTyParam(space, index, _, name) => {
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
ty::mk_param(tcx, space, index, name)
}
def::DefSelfTy(_) => {
// n.b.: resolve guarantees that the this type only appears in a
// trait, which we rely upon in various places when creating
// substs
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
ty::mk_self_type(tcx)
}
def::DefMod(id) => {
span_fatal!(tcx.sess, ast_ty.span, E0247,
"found module name used as a type: {}",
tcx.map.node_to_string(id.node));
}
def::DefPrimTy(_) => {
panic!("DefPrimTy arm missed in previous ast_ty_to_prim_ty call");
}
def::DefAssociatedTy(trait_did, _) => {
let opt_self_ty = if let ast::TyQPath(ref qpath) = ast_ty.node {
Some(&*qpath.self_type)
} else {
None
};
qpath_to_ty(this, rscope, ast_ty.span, opt_self_ty, trait_did,
&path.segments[path.segments.len()-2],
path.segments.last().unwrap())
}
def::DefAssociatedPath(provenance, assoc_ident) => {
associated_path_def_to_ty(this, ast_ty, provenance, assoc_ident.name)
}
_ => {
span_fatal!(tcx.sess, ast_ty.span, E0248,
"found value name used \
as a type: {:?}",
a_def);
}
}
}
ast::TyFixedLengthVec(ref ty, ref e) => {
match const_eval::eval_const_expr_partial(tcx, &**e, Some(tcx.types.uint)) {
Ok(ref r) => {
match *r {
const_eval::const_int(i) =>
ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty),
Some(i as uint)),
const_eval::const_uint(i) =>
ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty),
Some(i as uint)),
_ => {
span_fatal!(tcx.sess, ast_ty.span, E0249,
"expected constant expr for array length");
}
}
}
Err(ref r) => {
span_fatal!(tcx.sess, ast_ty.span, E0250,
"expected constant expr for array \
length: {}",
*r);
}
}
}
ast::TyTypeof(ref _e) => {
tcx.sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented");
}
ast::TyInfer => {
// TyInfer also appears as the type of arguments or return
// values in a ExprClosure, or as
// the type of local variables. Both of these cases are
// handled specially and will not descend into this routine.
this.ty_infer(ast_ty.span)
}
}
});
ast::TyPtr(ref mt) => {
ty::mk_ptr(tcx, ty::mt {
ty: ast_ty_to_ty(this, rscope, &*mt.ty),
mutbl: mt.mutbl
})
}
ast::TyRptr(ref region, ref mt) => {
let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region);
debug!("ty_rptr r={}", r.repr(this.tcx()));
let rscope1 =
&ObjectLifetimeDefaultRscope::new(
rscope,
Some(ty::ObjectLifetimeDefault::Specific(r)));
let t = ast_ty_to_ty(this, rscope1, &*mt.ty);
ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl})
}
ast::TyTup(ref fields) => {
let flds = fields.iter()
.map(|t| ast_ty_to_ty(this, rscope, &**t))
.collect();
ty::mk_tup(tcx, flds)
}
ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ),
ast::TyBareFn(ref bf) => {
if bf.decl.variadic && bf.abi != abi::C {
span_err!(tcx.sess, ast_ty.span, E0222,
"variadic function must have C calling convention");
}
let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl);
ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(bare_fn))
}
ast::TyPolyTraitRef(ref bounds) => {
conv_ty_poly_trait_ref(this, rscope, ast_ty.span, bounds)
}
ast::TyPath(ref path) | ast::TyQPath(ast::QPath { ref path, .. }) => {
let result = if let Some(&d) = tcx.def_map.borrow().get(&ast_ty.id) {
(d, 0)
} else if let Some(d) = tcx.partial_def_map.borrow().get(&ast_ty.id) {
(d.base_type, (d.extra_associated_types + 1) as usize)
} else {
tcx.sess.span_bug(ast_ty.span,
&format!("unbound path {}", ast_ty.repr(tcx)))
};
let (base_def, max_depth) = result;
let span = ast_ty.span; // Could be more granular.
let segments = &path.segments[..path.segments.len()-max_depth];
let base_ty = match base_def {
def::DefTrait(trait_def_id) => {
// N.B. this case overlaps somewhat with
// TyObjectSum, see that fn for details
let mut projection_bounds = Vec::new();
let trait_ref = object_path_to_poly_trait_ref(this,
rscope,
span,
trait_def_id,
segments.last().unwrap(),
&mut projection_bounds);
check_path_args(tcx, span, segments.init(), NO_TPS | NO_REGIONS);
trait_ref_to_object_type(this, rscope, span, trait_ref,
projection_bounds, &[])
}
def::DefTy(did, _) | def::DefStruct(did) => {
check_path_args(tcx, span, segments.init(), NO_TPS | NO_REGIONS);
ast_path_to_ty(this, rscope, span, did, segments.last().unwrap())
}
def::DefTyParam(space, index, _, name) => {
check_path_args(tcx, span, segments, NO_TPS | NO_REGIONS);
ty::mk_param(tcx, space, index, name)
}
def::DefSelfTy(_) => {
// n.b.: resolve guarantees that the this type only appears in a
// trait, which we rely upon in various places when creating
// substs
check_path_args(tcx, span, segments, NO_TPS | NO_REGIONS);
ty::mk_self_type(tcx)
}
def::DefAssociatedTy(trait_did, _) => {
let opt_self_ty = if let ast::TyQPath(ref qpath) = ast_ty.node {
Some(&*qpath.self_type)
} else {
None
};
check_path_args(tcx, span, &segments[..segments.len()-2],
NO_TPS | NO_REGIONS);
qpath_to_ty(this, rscope, span, opt_self_ty, trait_did,
&segments[segments.len()-2],
segments.last().unwrap())
}
def::DefMod(id) => {
tcx.sess.span_bug(span,
&format!("found module name used as a type: {}",
tcx.map.node_to_string(id.node)));
}
def::DefPrimTy(prim_ty) => {
prim_ty_to_ty(tcx, span, segments, prim_ty)
}
_ => {
span_fatal!(tcx.sess, span, E0248,
"found value name used as a type: {:?}", base_def);
}
};
// If any associated type segments remain, attempt to resolve them.
let mut ty = base_ty;
let mut def = base_def;
for depth in (0..max_depth).rev() {
if ty.sty == ty::ty_err {
break;
}
// This is pretty bad (it will fail except for T::A and Self::A).
let segment = &path.segments[path.segments.len()-depth-1];
let (a_ty, a_def) = associated_path_def_to_ty(this, span,
ty, def, segment);
ty = a_ty;
def = a_def;
}
if max_depth != 0 && ty.sty != ty::ty_err {
// Write back the new resolution.
tcx.def_map.borrow_mut().insert(ast_ty.id, def);
}
ty
}
ast::TyFixedLengthVec(ref ty, ref e) => {
match const_eval::eval_const_expr_partial(tcx, &**e, Some(tcx.types.uint)) {
Ok(r) => {
match r {
const_eval::const_int(i) =>
ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty),
Some(i as uint)),
const_eval::const_uint(i) =>
ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty),
Some(i as uint)),
_ => {
span_fatal!(tcx.sess, ast_ty.span, E0249,
"expected constant expr for array length");
}
}
}
Err(r) => {
span_fatal!(tcx.sess, ast_ty.span, E0250,
"expected constant expr for array length: {}", r);
}
}
}
ast::TyTypeof(ref _e) => {
tcx.sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented");
}
ast::TyInfer => {
// TyInfer also appears as the type of arguments or return
// values in a ExprClosure, or as
// the type of local variables. Both of these cases are
// handled specially and will not descend into this routine.
this.ty_infer(ast_ty.span)
}
};
tcx.ast_ty_to_ty_cache.borrow_mut().insert(ast_ty.id, ty::atttce_resolved(typ));
return typ;

View File

@ -1613,7 +1613,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
generics.regions.get_slice(TypeSpace));
Substs::new_type(tps, rps)
} else {
astconv::ast_path_substs_for_ty(self, self, &generics, path)
astconv::ast_path_substs_for_ty(self, self,
path.span,
&generics,
path.segments.last().unwrap())
};
let ty = self.instantiate_type_scheme(path.span, &substs, &decl_ty);
@ -4632,7 +4635,6 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
def::DefTrait(_) |
def::DefTy(..) |
def::DefAssociatedTy(..) |
def::DefAssociatedPath(..) |
def::DefPrimTy(_) |
def::DefTyParam(..) |
def::DefMod(..) |
@ -4731,7 +4733,6 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
def::DefVariant(..) |
def::DefTy(..) |
def::DefAssociatedTy(..) |
def::DefAssociatedPath(..) |
def::DefTrait(..) |
def::DefPrimTy(..) |
def::DefTyParam(..) => {

View File

@ -8,13 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-tidy-linelength
struct Foo {
x: isize
}
impl Fo { //~ERROR inherent implementations are not allowed for types not defined in the current module
impl Fo { //~ ERROR use of undeclared type name `Fo`
fn foo() {}
}

View File

@ -10,7 +10,7 @@
// ignore-tidy-linelength
impl B { //~ERROR inherent implementations are not allowed for types not defined in the current module
impl B { //~ ERROR use of undeclared type name `B`
}
fn main() {

View File

@ -14,7 +14,7 @@ mod a {
trait A {
}
impl A for a { //~ERROR found module name used as a type
impl A for a { //~ ERROR use of undeclared type name `a`
}
fn main() {

View File

@ -8,9 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-tidy-linelength
impl<T> Option<T> { //~ERROR inherent implementations are not allowed for types not defined in the current module
// FIXME(eddyb/UFCS) This should have a nicer error, but that's not possible just yet.
impl<T> Option<T> { //~ ERROR use of undeclared type name `Option`
pub fn foo(&self) { }
}