Skip to content

Commit

Permalink
Delegation: fix ICE on wrong instantiation
Browse files Browse the repository at this point in the history
  • Loading branch information
Bryanskiy committed Mar 26, 2024
1 parent b13a71a commit 1d657a5
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 20 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ hir_analysis_must_implement_not_function_span_note = required by this annotation
hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
hir_analysis_not_supported_delegation =
{$descr} is not supported yet
{$descr}
.label = callee defined here
hir_analysis_only_current_traits_arbitrary = only traits defined in the current crate can be implemented for arbitrary types
Expand Down
52 changes: 42 additions & 10 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use crate::hir_ty_lowering::errors::prohibit_assoc_item_binding;
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
use crate::middle::resolve_bound_vars as rbv;
use crate::require_c_abi_if_c_variadic;
use crate::rustc_middle::ty::TypeSuperVisitable;
use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::{
Expand All @@ -41,7 +42,7 @@ use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::ty::{
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
TypeVisitableExt,
TypeVisitable, TypeVisitableExt,
};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
use rustc_span::edit_distance::find_best_match_for_name;
Expand All @@ -52,6 +53,7 @@ use rustc_trait_selection::traits::wf::object_region_bounds;
use rustc_trait_selection::traits::{self, ObligationCtxt};

use std::fmt::Display;
use std::ops::ControlFlow;
use std::slice;

/// A path segment that is semantically allowed to have generic arguments.
Expand Down Expand Up @@ -2193,46 +2195,76 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&& let hir::FnRetTy::Return(ty) = decl.output
&& let hir::TyKind::InferDelegation(_, _) = ty.kind
{
try_emit("recursive delegation");
try_emit("recursive delegation is not supported yet");
}

let sig = self.tcx().fn_sig(sig_id).instantiate_identity();
if sig.output().has_opaque_types() {
try_emit("delegation to a function with opaque type");
try_emit("delegation to a function with opaque type is not supported yet");
}

let sig_generics = self.tcx().generics_of(sig_id);
let parent = self.tcx().parent(self.item_def_id());
let parent_generics = self.tcx().generics_of(parent);

let parent_is_trait = (self.tcx().def_kind(parent) == DefKind::Trait) as usize;
let parent_def_kind = self.tcx().def_kind(parent);
let parent_is_trait = (parent_def_kind == DefKind::Trait) as usize;
let sig_has_self = sig_generics.has_self as usize;

if sig_generics.count() > sig_has_self || parent_generics.count() > parent_is_trait {
try_emit("delegation with early bound generics");
try_emit("delegation with early bound generics is not supported yet");
}

// There is no way to instantiate `Self` param for caller if
// 1. callee is a trait method && callee contains `Self` param
// 2. parent item isn't a trait or impl
if let DefKind::AssocFn = self.tcx().def_kind(sig_id)
&& !matches!(parent_def_kind, DefKind::Impl { .. } | DefKind::Trait)
&& self.tcx().associated_item(sig_id).container
== ty::AssocItemContainer::TraitContainer
{
struct HasSelfParamVisitor;

impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for HasSelfParamVisitor {
type Result = ControlFlow<()>;

fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
// All early bound generics except `Self` are previously banned.
// It is enough to check only the `ty::Param`.
if matches!(ty.kind(), ty::Param(..)) {
return ControlFlow::Break(());
}

ty.super_visit_with(self)
}
}

if sig.visit_with(&mut HasSelfParamVisitor).is_break() {
try_emit("Couldn't instantiate `Self` callee type");
}
}

if self.tcx().asyncness(sig_id) == ty::Asyncness::Yes {
try_emit("delegation to async functions");
try_emit("delegation to async functions is not supported yet");
}

if self.tcx().constness(sig_id) == hir::Constness::Const {
try_emit("delegation to const functions");
try_emit("delegation to const functions is not supported yet");
}

if sig.c_variadic() {
try_emit("delegation to variadic functions");
try_emit("delegation to variadic functions is not supported yet");
// variadic functions are also `unsafe` and `extern "C"`.
// Do not emit same error multiple times.
return error_occured;
}

if let hir::Unsafety::Unsafe = sig.unsafety() {
try_emit("delegation to unsafe functions");
try_emit("delegation to unsafe functions is not supported yet");
}

if abi::Abi::Rust != sig.abi() {
try_emit("delegation to non Rust ABI functions");
try_emit("delegation to non Rust ABI functions is not supported yet");
}

error_occured
Expand Down
20 changes: 20 additions & 0 deletions tests/ui/delegation/not-supported.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,26 @@ mod generics {
}
}

mod generics_self_forbidden {
trait Trait {
fn foo1(&self, x: i32) -> i32 { 0 }
fn foo2(_: Option<&Self>) {}
fn foo3(_: i32) {}
fn foo4(_: i32) {}
}

struct S;
impl Trait for S {}

reuse Trait::foo1;
//~^ ERROR Couldn't instantiate `Self` callee type
reuse Trait::foo2;
//~^ ERROR Couldn't instantiate `Self` callee type
reuse Trait::foo3;
//~^ ERROR type annotations needed
reuse <S as Trait>::foo4;
}

mod opaque {
trait Trait {}
impl Trait for () {}
Expand Down
45 changes: 36 additions & 9 deletions tests/ui/delegation/not-supported.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,26 @@ LL | fn foo2<T>(&self, x: T) -> T { x }
LL | reuse Trait::foo2 { &self.0 }
| ^^^^

error: Couldn't instantiate `Self` callee type
--> $DIR/not-supported.rs:75:18
|
LL | fn foo1(&self, x: i32) -> i32 { 0 }
| ----------------------------- callee defined here
...
LL | reuse Trait::foo1;
| ^^^^

error: Couldn't instantiate `Self` callee type
--> $DIR/not-supported.rs:77:18
|
LL | fn foo2(_: Option<&Self>) {}
| ------------------------- callee defined here
...
LL | reuse Trait::foo2;
| ^^^^

error: delegation with early bound generics is not supported yet
--> $DIR/not-supported.rs:74:21
--> $DIR/not-supported.rs:94:21
|
LL | pub fn opaque_arg(_: impl Trait) -> i32 { 0 }
| --------------------------------------- callee defined here
Expand All @@ -125,7 +143,7 @@ LL | reuse to_reuse::opaque_arg;
| ^^^^^^^^^^

error: delegation to a function with opaque type is not supported yet
--> $DIR/not-supported.rs:76:21
--> $DIR/not-supported.rs:96:21
|
LL | pub fn opaque_ret() -> impl Trait { unimplemented!() }
| --------------------------------- callee defined here
Expand All @@ -134,7 +152,7 @@ LL | reuse to_reuse::opaque_ret;
| ^^^^^^^^^^

error: delegation to unsafe functions is not supported yet
--> $DIR/not-supported.rs:88:21
--> $DIR/not-supported.rs:108:21
|
LL | pub unsafe fn unsafe_fn() {}
| ------------------------- callee defined here
Expand All @@ -143,7 +161,7 @@ LL | reuse to_reuse::unsafe_fn;
| ^^^^^^^^^

error: delegation to non Rust ABI functions is not supported yet
--> $DIR/not-supported.rs:90:21
--> $DIR/not-supported.rs:110:21
|
LL | pub extern "C" fn extern_fn() {}
| ----------------------------- callee defined here
Expand All @@ -152,7 +170,7 @@ LL | reuse to_reuse::extern_fn;
| ^^^^^^^^^

error: delegation to variadic functions is not supported yet
--> $DIR/not-supported.rs:92:21
--> $DIR/not-supported.rs:112:21
|
LL | pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) {}
| ------------------------------------------------------------- callee defined here
Expand All @@ -161,7 +179,7 @@ LL | reuse to_reuse::variadic_fn;
| ^^^^^^^^^^^

error: delegation to const functions is not supported yet
--> $DIR/not-supported.rs:94:21
--> $DIR/not-supported.rs:114:21
|
LL | pub const fn const_fn() {}
| ----------------------- callee defined here
Expand All @@ -170,15 +188,24 @@ LL | reuse to_reuse::const_fn;
| ^^^^^^^^

error: recursive delegation is not supported yet
--> $DIR/not-supported.rs:107:22
--> $DIR/not-supported.rs:127:22
|
LL | pub reuse to_reuse2::foo;
| --- callee defined here
...
LL | reuse to_reuse1::foo;
| ^^^

error: aborting due to 19 previous errors; 1 warning emitted
error[E0283]: type annotations needed
--> $DIR/not-supported.rs:79:11
|
LL | reuse Trait::foo3;
| ^^^^^^^^^^^ cannot infer type
|
= note: cannot satisfy `_: generics_self_forbidden::Trait`
= help: the trait `generics_self_forbidden::Trait` is implemented for `generics_self_forbidden::S`

error: aborting due to 22 previous errors; 1 warning emitted

Some errors have detailed explanations: E0049, E0195.
Some errors have detailed explanations: E0049, E0195, E0283.
For more information about an error, try `rustc --explain E0049`.

0 comments on commit 1d657a5

Please sign in to comment.