diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index fa103099e643f..e5953fb5f970c 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -38,7 +38,7 @@ pub(super) enum Owners<'a, 'hir> { } impl<'hir> Owners<'_, 'hir> { - fn get_or_insert_mut(&mut self, def_id: LocalDefId) -> &mut hir::MaybeOwner<'hir> { + pub(super) fn get_or_insert_mut(&mut self, def_id: LocalDefId) -> &mut hir::MaybeOwner<'hir> { match self { Owners::IndexVec(index_vec) => { index_vec.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5fcc8f0161194..1d28dfd269050 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -39,6 +39,7 @@ use std::mem; use std::sync::Arc; use rustc_ast::node_id::NodeMap; +use rustc_ast::visit::AssocCtxt; use rustc_ast::{self as ast, *}; use rustc_attr_parsing::{AttributeParser, Late, OmitDoc}; use rustc_data_structures::fingerprint::Fingerprint; @@ -633,13 +634,29 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> { let mut delayed_ids: FxIndexSet = Default::default(); for def_id in ast_index.indices() { - match &ast_index[def_id] { - AstOwner::Item(Item { kind: ItemKind::Delegation { .. }, .. }) - | AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation { .. }, .. }, _) => { - delayed_ids.insert(def_id); + let kind = match &ast_index[def_id] { + AstOwner::Item(Item { kind: ItemKind::Delegation { .. }, .. }) => { + Some(hir::DelayedOwnerKind::Item) } - _ => lowerer.lower_node(def_id), + AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation { .. }, .. }, ctx) => { + match ctx { + AssocCtxt::Trait => Some(hir::DelayedOwnerKind::TraitItem), + AssocCtxt::Impl { .. } => Some(hir::DelayedOwnerKind::ImplItem), + } + } + _ => None, }; + + if let Some(kind) = kind { + delayed_ids.insert(def_id); + + let owner = lowerer.owners.get_or_insert_mut(def_id); + if let hir::MaybeOwner::Phantom = owner { + *owner = hir::MaybeOwner::Delayed(kind) + } + } else { + lowerer.lower_node(def_id); + } } // Don't hash unless necessary, because it's expensive. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 57cf42cc54794..cd82940dba31a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1641,10 +1641,18 @@ impl<'tcx> OwnerInfo<'tcx> { } } +#[derive(Copy, Clone, Debug, HashStable_Generic)] +pub enum DelayedOwnerKind { + Item, + ImplItem, + TraitItem, +} + #[derive(Copy, Clone, Debug, HashStable_Generic)] pub enum MaybeOwner<'tcx> { Owner(&'tcx OwnerInfo<'tcx>), NonOwner(HirId), + Delayed(DelayedOwnerKind), /// Used as a placeholder for unused LocalDefId. Phantom, } @@ -1653,13 +1661,17 @@ impl<'tcx> MaybeOwner<'tcx> { pub fn as_owner(self) -> Option<&'tcx OwnerInfo<'tcx>> { match self { MaybeOwner::Owner(i) => Some(i), - MaybeOwner::NonOwner(_) | MaybeOwner::Phantom => None, + _ => None, } } pub fn unwrap(self) -> &'tcx OwnerInfo<'tcx> { self.as_owner().unwrap_or_else(|| panic!("Not a HIR owner")) } + + pub fn expect_delayed(&self) -> DelayedOwnerKind { + if let MaybeOwner::Delayed(kind) = self { *kind } else { panic!("not a delayed owner") } + } } #[derive(Debug, Clone, Copy, HashStable_Generic)] diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 25ef56f8b0f2c..75b630420ce3e 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -117,6 +117,7 @@ pub trait HirTyCtxt<'hir> { fn hir_trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir>; fn hir_impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir>; fn hir_foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir>; + fn is_delayed(&self, id: LocalDefId) -> bool; } // Used when no tcx is actually available, forcing manual implementation of nested visitors. @@ -139,6 +140,9 @@ impl<'hir> HirTyCtxt<'hir> for ! { fn hir_foreign_item(&self, _: ForeignItemId) -> &'hir ForeignItem<'hir> { unreachable!(); } + fn is_delayed(&self, _: LocalDefId) -> bool { + unreachable!() + } } pub mod nested_filter { @@ -226,6 +230,8 @@ pub trait Visitor<'v>: Sized { /// or `ControlFlow`. type Result: VisitorResult = (); + const VISIT_DELAYED: bool = true; + /// If `type NestedFilter` is set to visit nested items, this method /// must also be overridden to provide a map to retrieve nested items. fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { @@ -244,18 +250,22 @@ pub trait Visitor<'v>: Sized { /// this method is if you want a nested pattern but cannot supply a /// `TyCtxt`; see `maybe_tcx` for advice. fn visit_nested_item(&mut self, id: ItemId) -> Self::Result { - if Self::NestedFilter::INTER { + if self.should_visit_maybe_delayed_inter(id.owner_id.def_id) { let item = self.maybe_tcx().hir_item(id); try_visit!(self.visit_item(item)); } Self::Result::output() } + fn should_visit_maybe_delayed_inter(&mut self, id: LocalDefId) -> bool { + Self::NestedFilter::INTER && (Self::VISIT_DELAYED || !self.maybe_tcx().is_delayed(id)) + } + /// Like `visit_nested_item()`, but for trait items. See /// `visit_nested_item()` for advice on when to override this /// method. fn visit_nested_trait_item(&mut self, id: TraitItemId) -> Self::Result { - if Self::NestedFilter::INTER { + if self.should_visit_maybe_delayed_inter(id.owner_id.def_id) { let item = self.maybe_tcx().hir_trait_item(id); try_visit!(self.visit_trait_item(item)); } @@ -266,7 +276,7 @@ pub trait Visitor<'v>: Sized { /// `visit_nested_item()` for advice on when to override this /// method. fn visit_nested_impl_item(&mut self, id: ImplItemId) -> Self::Result { - if Self::NestedFilter::INTER { + if self.should_visit_maybe_delayed_inter(id.owner_id.def_id) { let item = self.maybe_tcx().hir_impl_item(id); try_visit!(self.visit_impl_item(item)); } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 6b7f31521d441..f1404ca8fe2dd 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1028,6 +1028,10 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( /// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses. /// This function never fails. fn run_required_analyses(tcx: TyCtxt<'_>) { + // Prefetches hir_crate_items to prevent multiple threads from blocking on it later. + // Also forces all delayed owners to be lowered and drops AST crate after it. + tcx.force_delayed_owners_lowering(); + if tcx.sess.opts.unstable_opts.input_stats { rustc_passes::input_stats::print_hir_stats(tcx); } @@ -1036,11 +1040,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { #[cfg(all(not(doc), debug_assertions))] rustc_passes::hir_id_validator::check_crate(tcx); - // Prefetch this to prevent multiple threads from blocking on it later. - // This is needed since the `hir_id_validator::check_crate` call above is not guaranteed - // to use `hir_crate_items`. - tcx.ensure_done().hir_crate_items(()); - let sess = tcx.sess; sess.time("misc_checking_1", || { par_fns(&mut [ diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 499c6dae060bf..144fd9087cb89 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -7,7 +7,7 @@ use rustc_ast::visit::{VisitorResult, walk_list}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, spawn, try_par_for_each_in}; +use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, try_par_for_each_in}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId, LocalModDefId}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; @@ -1115,6 +1115,10 @@ impl<'tcx> intravisit::HirTyCtxt<'tcx> for TyCtxt<'tcx> { fn hir_foreign_item(&self, id: ForeignItemId) -> &'tcx ForeignItem<'tcx> { (*self).hir_foreign_item(id) } + + fn is_delayed(&self, id: LocalDefId) -> bool { + (*self).hir_crate(()).delayed_ids.contains(&id) + } } impl<'tcx> pprust_hir::PpAnn for TyCtxt<'tcx> { @@ -1212,8 +1216,14 @@ fn upstream_crates(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> { upstream_crates } +#[derive(Clone, Copy)] +enum ItemCollectionKind { + Crate, + Mod(LocalModDefId), +} + pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> ModuleItems { - let mut collector = ItemCollector::new(tcx, false); + let mut collector = ItemCollector::new(tcx, ItemCollectionKind::Mod(module_id)); let (hir_mod, span, hir_id) = tcx.hir_get_module(module_id); collector.visit_mod(hir_mod, span, hir_id); @@ -1245,26 +1255,8 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod } } -fn force_delayed_owners_lowering(tcx: TyCtxt<'_>) { - let krate = tcx.hir_crate(()); - for &id in &krate.delayed_ids { - tcx.ensure_done().lower_delayed_owner(id); - } - - let (_, krate) = krate.delayed_resolver.steal(); - let prof = tcx.sess.prof.clone(); - - // Drop AST to free memory. It can be expensive so try to drop it on a separate thread. - spawn(move || { - let _timer = prof.verbose_generic_activity("drop_ast"); - drop(krate); - }); -} - pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { - force_delayed_owners_lowering(tcx); - - let mut collector = ItemCollector::new(tcx, true); + let mut collector = ItemCollector::new(tcx, ItemCollectionKind::Crate); // A "crate collector" and "module collector" start at a // module item (the former starts at the crate root) but only @@ -1327,9 +1319,9 @@ struct ItemCollector<'tcx> { } impl<'tcx> ItemCollector<'tcx> { - fn new(tcx: TyCtxt<'tcx>, crate_collector: bool) -> ItemCollector<'tcx> { - ItemCollector { - crate_collector, + fn new(tcx: TyCtxt<'tcx>, collection_kind: ItemCollectionKind) -> ItemCollector<'tcx> { + let mut collector = ItemCollector { + crate_collector: matches!(collection_kind, ItemCollectionKind::Crate), tcx, submodules: Vec::default(), items: Vec::default(), @@ -1341,12 +1333,34 @@ impl<'tcx> ItemCollector<'tcx> { nested_bodies: Vec::default(), delayed_lint_items: Vec::default(), eiis: Vec::default(), + }; + + let delayed_kinds = tcx.hir_crate(()).delayed_owners_kinds(); + let delayed_kinds = delayed_kinds.filter(|(id, _)| match collection_kind { + ItemCollectionKind::Crate => true, + ItemCollectionKind::Mod(mod_id) => tcx.parent_module_from_def_id(*id) == mod_id, + }); + + // FIXME(fn_delegation): need to add delayed lints, eiis + for (def_id, kind) in delayed_kinds { + let owner_id = OwnerId { def_id }; + + match kind { + DelayedOwnerKind::Item => collector.items.push(ItemId { owner_id }), + DelayedOwnerKind::ImplItem => collector.impl_items.push(ImplItemId { owner_id }), + DelayedOwnerKind::TraitItem => collector.trait_items.push(TraitItemId { owner_id }), + }; + + collector.body_owners.push(def_id); } + + collector } } impl<'hir> Visitor<'hir> for ItemCollector<'hir> { type NestedFilter = nested_filter::All; + const VISIT_DELAYED: bool = false; fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { self.tcx diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index ad56e462d2934..63d48326ebdcb 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -14,7 +14,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; -use rustc_data_structures::sync::{DynSend, DynSync, try_par_for_each_in}; +use rustc_data_structures::sync::{DynSend, DynSync, spawn, try_par_for_each_in}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::lints::DelayedLint; @@ -64,7 +64,8 @@ impl<'hir> Crate<'hir> { // which is greater than delayed LocalDefId, we use IndexVec for owners, // so we will call ensure_contains_elem which will grow it. if let Some(owner) = self.owners.get(def_id) - && (self.delayed_ids.is_empty() || !matches!(owner, MaybeOwner::Phantom)) + && (self.delayed_ids.is_empty() + || !matches!(owner, MaybeOwner::Phantom | MaybeOwner::Delayed(_))) { return *owner; } @@ -75,6 +76,10 @@ impl<'hir> Crate<'hir> { tcx.delayed_owner(def_id) } + + pub fn delayed_owners_kinds(&self) -> impl Iterator { + self.delayed_ids.iter().copied().map(|id| (id, self.owners[id].expect_delayed())) + } } impl HashStable for Crate<'_> { @@ -207,6 +212,24 @@ impl ModuleItems { } impl<'tcx> TyCtxt<'tcx> { + pub fn force_delayed_owners_lowering(self) { + let krate = self.hir_crate(()); + self.ensure_done().hir_crate_items(()); + + for &id in &krate.delayed_ids { + self.ensure_done().lower_delayed_owner(id); + } + + let (_, krate) = krate.delayed_resolver.steal(); + let prof = self.sess.prof.clone(); + + // Drop AST to free memory. It can be expensive so try to drop it on a separate thread. + spawn(move || { + let _timer = prof.verbose_generic_activity("drop_ast"); + drop(krate); + }); + } + pub fn parent_module(self, id: HirId) -> LocalModDefId { if !id.is_owner() && self.def_kind(id.owner) == DefKind::Mod { LocalModDefId::new_unchecked(id.owner.def_id) @@ -475,7 +498,8 @@ pub fn provide(providers: &mut Providers) { providers.local_def_id_to_hir_id = |tcx, def_id| match tcx.hir_crate(()).owner(tcx, def_id) { MaybeOwner::Owner(_) => HirId::make_owner(def_id), MaybeOwner::NonOwner(hir_id) => hir_id, - MaybeOwner::Phantom => bug!("No HirId for {:?}", def_id), + MaybeOwner::Phantom => bug!("no HirId for {:?}", def_id), + MaybeOwner::Delayed(_) => bug!("delayed owner should be lowered {:?}", def_id), }; providers.opt_hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owner(tcx, id).as_owner().map(|i| &i.nodes); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 6718505bdefd9..b0fb0d6c909ba 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -904,6 +904,7 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { return; } + tcx.force_delayed_owners_lowering(); for owner_id in tcx.hir_crate_items(()).delayed_lint_items() { if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) { for lint in &delayed_lints.lints { diff --git a/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr index ae5d0e8fa2965..cbbf5c0a74787 100644 --- a/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr +++ b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr @@ -43,15 +43,6 @@ help: consider introducing lifetime `'a` here LL | impl<'a> Trait for Z { | ++++ -error[E0599]: no function or associated item named `new` found for struct `InvariantRef<'a, T>` in the current scope - --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:9:41 - | -LL | pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>); - | -------------------------------------- function or associated item `new` not found for this struct -... -LL | pub const NEW: Self = InvariantRef::new(&()); - | ^^^ function or associated item not found in `InvariantRef<'_, _>` - error[E0277]: the trait bound `u8: Trait` is not satisfied --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12 | @@ -119,6 +110,15 @@ LL | reuse ::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW found struct `InvariantRef<'_, ()>` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error[E0599]: no function or associated item named `new` found for struct `InvariantRef<'a, T>` in the current scope + --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:9:41 + | +LL | pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>); + | -------------------------------------- function or associated item `new` not found for this struct +... +LL | pub const NEW: Self = InvariantRef::new(&()); + | ^^^ function or associated item not found in `InvariantRef<'_, _>` + error: aborting due to 10 previous errors Some errors have detailed explanations: E0261, E0277, E0308, E0599. diff --git a/tests/ui/delegation/generics/const-type-ice-153499.stderr b/tests/ui/delegation/generics/const-type-ice-153499.stderr index 02fd7197dcdc3..851c2f14efbfe 100644 --- a/tests/ui/delegation/generics/const-type-ice-153499.stderr +++ b/tests/ui/delegation/generics/const-type-ice-153499.stderr @@ -10,18 +10,18 @@ LL + use std::ffi::CStr; | error: using function pointers as const generic parameters is forbidden - --> $DIR/const-type-ice-153499.rs:4:29 + --> $DIR/const-type-ice-153499.rs:10:14 | -LL | trait Trait<'a, T, const F: fn(&CStr) -> usize> { - | ^^^^^^^^^^^^^^^^^^ +LL | reuse Trait::foo; + | ^^^ | = note: the only supported types are integers, `bool`, and `char` error: using function pointers as const generic parameters is forbidden - --> $DIR/const-type-ice-153499.rs:10:14 + --> $DIR/const-type-ice-153499.rs:4:29 | -LL | reuse Trait::foo; - | ^^^ +LL | trait Trait<'a, T, const F: fn(&CStr) -> usize> { + | ^^^^^^^^^^^^^^^^^^ | = note: the only supported types are integers, `bool`, and `char` diff --git a/tests/ui/delegation/generics/query-cycle-oom-154169.rs b/tests/ui/delegation/generics/query-cycle-oom-154169.rs new file mode 100644 index 0000000000000..1b28379befcd9 --- /dev/null +++ b/tests/ui/delegation/generics/query-cycle-oom-154169.rs @@ -0,0 +1,39 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod test_1 { + trait Trait { + fn foo(&self, x: T) -> S { x } + //~^ ERROR: missing generics for struct `test_1::S` + } + struct F; + + struct S(F, T); + + impl Trait for S { + reuse to_reuse::foo { &self.0 } + //~^ ERROR: cannot find module or crate `to_reuse` in this scope + } +} + +mod test_2 { + trait Trait { + fn foo() -> Self::Assoc; + //~^ ERROR: associated type `Assoc` not found for `Self` + fn bar(&self) -> u8; + } + + impl Trait for u8 { + //~^ ERROR: not all trait items implemented, missing: `foo` + fn bar(&self) -> u8 { 1 } + } + + struct S(u8); + + impl Trait for S { + reuse Trait::* { &self.0 } + fn bar(&self) -> u8 { 2 } + } +} + +fn main() {} diff --git a/tests/ui/delegation/generics/query-cycle-oom-154169.stderr b/tests/ui/delegation/generics/query-cycle-oom-154169.stderr new file mode 100644 index 0000000000000..7836454d4019e --- /dev/null +++ b/tests/ui/delegation/generics/query-cycle-oom-154169.stderr @@ -0,0 +1,43 @@ +error[E0107]: missing generics for struct `test_1::S` + --> $DIR/query-cycle-oom-154169.rs:6:32 + | +LL | fn foo(&self, x: T) -> S { x } + | ^ expected 1 generic argument + | +note: struct defined here, with 1 generic parameter: `T` + --> $DIR/query-cycle-oom-154169.rs:11:12 + | +LL | struct S(F, T); + | ^ - +help: add missing generic argument + | +LL | fn foo(&self, x: T) -> S { x } + | +++ + +error[E0220]: associated type `Assoc` not found for `Self` + --> $DIR/query-cycle-oom-154169.rs:21:27 + | +LL | fn foo() -> Self::Assoc; + | ^^^^^ associated type `Assoc` not found + +error[E0046]: not all trait items implemented, missing: `foo` + --> $DIR/query-cycle-oom-154169.rs:26:5 + | +LL | fn foo() -> Self::Assoc; + | ------------------------ `foo` from trait +... +LL | impl Trait for u8 { + | ^^^^^^^^^^^^^^^^^ missing `foo` in implementation + +error[E0433]: cannot find module or crate `to_reuse` in this scope + --> $DIR/query-cycle-oom-154169.rs:14:15 + | +LL | reuse to_reuse::foo { &self.0 } + | ^^^^^^^^ use of unresolved module or unlinked crate `to_reuse` + | + = help: you might be missing a crate named `to_reuse` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0046, E0107, E0220, E0433. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/delegation/ice-issue-122550.stderr b/tests/ui/delegation/ice-issue-122550.stderr index 01355c8ad921c..c0b6305227a07 100644 --- a/tests/ui/delegation/ice-issue-122550.stderr +++ b/tests/ui/delegation/ice-issue-122550.stderr @@ -1,9 +1,3 @@ -error[E0308]: mismatched types - --> $DIR/ice-issue-122550.rs:5:35 - | -LL | fn description(&self) -> &str {} - | ^^ expected `&str`, found `()` - error[E0277]: the trait bound `S: Trait` is not satisfied --> $DIR/ice-issue-122550.rs:13:12 | @@ -37,6 +31,12 @@ note: method defined here LL | fn description(&self) -> &str {} | ^^^^^^^^^^^ ----- +error[E0308]: mismatched types + --> $DIR/ice-issue-122550.rs:5:35 + | +LL | fn description(&self) -> &str {} + | ^^ expected `&str`, found `()` + error: aborting due to 3 previous errors Some errors have detailed explanations: E0277, E0308.