提交 0f49254b 编写于 作者: E Eduard Burtescu

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

上级 5809f8ae
......@@ -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
}
......
......@@ -444,10 +444,6 @@ fn tr(&self, dcx: &DecodeContext) -> 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)),
......
......@@ -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 @@ pub fn map<F>(self, f: F) -> MethodProvenance where
}
}
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 @@ pub fn def_id(&self) -> ast::DefId {
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) |
......
......@@ -582,7 +582,7 @@ pub fn cat_def(&self,
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,
......
......@@ -46,7 +46,7 @@
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 @@ fn new(arena: &'tcx TypedArena<TyS<'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()),
......
......@@ -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,
......
......@@ -940,7 +940,7 @@ fn handle_external_def(&mut self,
is_public,
DUMMY_SP)
}
DefTy(..) | DefAssociatedTy(..) | DefAssociatedPath(..) => {
DefTy(..) | DefAssociatedTy(..) => {
debug!("(building reduced graph for external \
crate) building type {}", final_ident);
......
......@@ -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 @@ fn new(session: &'a Session,
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 @@ fn resolve_trait_reference(&mut self,
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 @@ fn resolve_generics(&mut self, generics: &Generics) {
&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 @@ fn resolve_implementation(&mut self,
});
});
});
// 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 @@ fn resolve_type(&mut self, ty: &Ty) {
// 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 @@ fn resolve_type(&mut self, ty: &Ty) {
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 @@ struct or enum variant",
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 @@ struct or enum variant",
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 @@ struct or enum variant",
// 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 @@ struct or enum variant",
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 @@ fn resolve_path(&mut self,
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 @@ fn resolve_path(&mut self,
_ => ()
}
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 @@ fn resolve_expr(&mut self, expr: &Expr) {
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 @@ fn resolve_expr(&mut self, expr: &Expr) {
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 @@ fn resolve_expr(&mut self, expr: &Expr) {
}
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 @@ fn add_trait_info(found_traits: &mut Vec<DefId>,
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 @@ fn dump_module(&mut self, module_: Rc<Module>) {
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,
......
......@@ -238,7 +238,6 @@ fn lookup_def_kind(&self, ref_id: NodeId, span: Span) -> Option<recorder::Row> {
def::DefStruct(_) => Some(recorder::StructRef),
def::DefTy(..) |
def::DefAssociatedTy(..) |
def::DefAssociatedPath(..) |
def::DefTrait(_) => Some(recorder::TypeRef),
def::DefStatic(_, _) |
def::DefConst(_) |
......
......@@ -210,7 +210,7 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
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 {:?} \
......
此差异已折叠。
......@@ -1613,7 +1613,10 @@ fn instantiate_struct_literal_ty(&self,
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(..) => {
......
......@@ -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() {}
}
......
......@@ -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() {
......
......@@ -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() {
......
......@@ -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) { }
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册