Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
1bb6ae58
R
Rust
项目概览
int
/
Rust
12 个月 前同步成功
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Rust
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
1bb6ae58
编写于
7月 26, 2023
作者:
M
Michael Goulet
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Rework upcasting
上级
fcf3006e
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
297 addition
and
104 deletion
+297
-104
compiler/rustc_infer/src/infer/at.rs
compiler/rustc_infer/src/infer/at.rs
+28
-0
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
+8
-0
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/mod.rs
+2
-0
compiler/rustc_middle/src/traits/solve/inspect.rs
compiler/rustc_middle/src/traits/solve/inspect.rs
+8
-5
compiler/rustc_middle/src/traits/solve/inspect/format.rs
compiler/rustc_middle/src/traits/solve/inspect/format.rs
+5
-2
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/print/pretty.rs
+2
-1
compiler/rustc_trait_selection/src/solve/trait_goals.rs
compiler/rustc_trait_selection/src/solve/trait_goals.rs
+88
-37
compiler/rustc_trait_selection/src/traits/select/confirmation.rs
...r/rustc_trait_selection/src/traits/select/confirmation.rs
+80
-59
tests/ui/traits/trait-upcasting/fewer-associated.rs
tests/ui/traits/trait-upcasting/fewer-associated.rs
+25
-0
tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr
...s/trait-upcasting/illegal-upcast-from-impl.current.stderr
+14
-0
tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr
...aits/trait-upcasting/illegal-upcast-from-impl.next.stderr
+14
-0
tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs
tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs
+23
-0
未找到文件。
compiler/rustc_infer/src/infer/at.rs
浏览文件 @
1bb6ae58
...
...
@@ -481,3 +481,31 @@ fn to_trace(
TypeTrace
{
cause
:
cause
.clone
(),
values
:
Sigs
(
ExpectedFound
::
new
(
a_is_expected
,
a
,
b
))
}
}
}
impl
<
'tcx
>
ToTrace
<
'tcx
>
for
ty
::
PolyExistentialTraitRef
<
'tcx
>
{
fn
to_trace
(
cause
:
&
ObligationCause
<
'tcx
>
,
a_is_expected
:
bool
,
a
:
Self
,
b
:
Self
,
)
->
TypeTrace
<
'tcx
>
{
TypeTrace
{
cause
:
cause
.clone
(),
values
:
ExistentialTraitRef
(
ExpectedFound
::
new
(
a_is_expected
,
a
,
b
)),
}
}
}
impl
<
'tcx
>
ToTrace
<
'tcx
>
for
ty
::
PolyExistentialProjection
<
'tcx
>
{
fn
to_trace
(
cause
:
&
ObligationCause
<
'tcx
>
,
a_is_expected
:
bool
,
a
:
Self
,
b
:
Self
,
)
->
TypeTrace
<
'tcx
>
{
TypeTrace
{
cause
:
cause
.clone
(),
values
:
ExistentialProjection
(
ExpectedFound
::
new
(
a_is_expected
,
a
,
b
)),
}
}
}
compiler/rustc_infer/src/infer/error_reporting/mod.rs
浏览文件 @
1bb6ae58
...
...
@@ -1635,6 +1635,12 @@ enum Mismatch<'a> {
(
false
,
Mismatch
::
Fixed
(
self
.tcx
.def_descr
(
expected
.def_id
)))
}
ValuePairs
::
Regions
(
_
)
=>
(
false
,
Mismatch
::
Fixed
(
"lifetime"
)),
ValuePairs
::
ExistentialTraitRef
(
_
)
=>
{
(
false
,
Mismatch
::
Fixed
(
"existential trait ref"
))
}
ValuePairs
::
ExistentialProjection
(
_
)
=>
{
(
false
,
Mismatch
::
Fixed
(
"existential projection"
))
}
};
let
Some
(
vals
)
=
self
.values_str
(
values
)
else
{
// Derived error. Cancel the emitter.
...
...
@@ -2139,6 +2145,8 @@ fn values_str(
infer
::
Regions
(
exp_found
)
=>
self
.expected_found_str
(
exp_found
),
infer
::
Terms
(
exp_found
)
=>
self
.expected_found_str_term
(
exp_found
),
infer
::
Aliases
(
exp_found
)
=>
self
.expected_found_str
(
exp_found
),
infer
::
ExistentialTraitRef
(
exp_found
)
=>
self
.expected_found_str
(
exp_found
),
infer
::
ExistentialProjection
(
exp_found
)
=>
self
.expected_found_str
(
exp_found
),
infer
::
TraitRefs
(
exp_found
)
=>
{
let
pretty_exp_found
=
ty
::
error
::
ExpectedFound
{
expected
:
exp_found
.expected
.print_only_trait_path
(),
...
...
compiler/rustc_infer/src/infer/mod.rs
浏览文件 @
1bb6ae58
...
...
@@ -374,6 +374,8 @@ pub enum ValuePairs<'tcx> {
TraitRefs
(
ExpectedFound
<
ty
::
TraitRef
<
'tcx
>>
),
PolyTraitRefs
(
ExpectedFound
<
ty
::
PolyTraitRef
<
'tcx
>>
),
Sigs
(
ExpectedFound
<
ty
::
FnSig
<
'tcx
>>
),
ExistentialTraitRef
(
ExpectedFound
<
ty
::
PolyExistentialTraitRef
<
'tcx
>>
),
ExistentialProjection
(
ExpectedFound
<
ty
::
PolyExistentialProjection
<
'tcx
>>
),
}
impl
<
'tcx
>
ValuePairs
<
'tcx
>
{
...
...
compiler/rustc_middle/src/traits/solve/inspect.rs
浏览文件 @
1bb6ae58
...
...
@@ -73,12 +73,15 @@ pub struct GoalCandidate<'tcx> {
pub
enum
CandidateKind
<
'tcx
>
{
/// Probe entered when normalizing the self ty during candidate assembly
NormalizedSelfTyAssembly
,
DynUpcastingAssembly
,
/// A normal candidate for proving a goal
Candidate
{
name
:
String
,
result
:
QueryResult
<
'tcx
>
,
},
Candidate
{
name
:
String
,
result
:
QueryResult
<
'tcx
>
},
/// Used in the probe that wraps normalizing the non-self type for the unsize
/// trait, which is also structurally matched on.
UnsizeAssembly
,
/// During upcasting from some source object to target object type, used to
/// do a probe to find out what projection type(s) may be used to prove that
/// the source type upholds all of the target type's object bounds.
UpcastProbe
,
}
impl
Debug
for
GoalCandidate
<
'_
>
{
fn
fmt
(
&
self
,
f
:
&
mut
std
::
fmt
::
Formatter
<
'_
>
)
->
std
::
fmt
::
Result
{
...
...
compiler/rustc_middle/src/traits/solve/inspect/format.rs
浏览文件 @
1bb6ae58
...
...
@@ -100,8 +100,11 @@ pub(super) fn format_candidate(&mut self, candidate: &GoalCandidate<'_>) -> std:
CandidateKind
::
NormalizedSelfTyAssembly
=>
{
writeln!
(
self
.f
,
"NORMALIZING SELF TY FOR ASSEMBLY:"
)
}
CandidateKind
::
DynUpcastingAssembly
=>
{
writeln!
(
self
.f
,
"ASSEMBLING CANDIDATES FOR DYN UPCASTING:"
)
CandidateKind
::
UnsizeAssembly
=>
{
writeln!
(
self
.f
,
"ASSEMBLING CANDIDATES FOR UNSIZING:"
)
}
CandidateKind
::
UpcastProbe
=>
{
writeln!
(
self
.f
,
"PROBING FOR PROJECTION COMPATIBILITY FOR UPCASTING:"
)
}
CandidateKind
::
Candidate
{
name
,
result
}
=>
{
writeln!
(
self
.f
,
"CANDIDATE {name}: {result:?}"
)
...
...
compiler/rustc_middle/src/ty/print/pretty.rs
浏览文件 @
1bb6ae58
...
...
@@ -2734,8 +2734,9 @@ pub struct PrintClosureAsImpl<'tcx> {
// HACK(eddyb) these are exhaustive instead of generic,
// because `for<'tcx>` isn't possible yet.
ty
::
PolyExistentialPredicate
<
'tcx
>
,
ty
::
PolyExistentialProjection
<
'tcx
>
,
ty
::
PolyExistentialTraitRef
<
'tcx
>
,
ty
::
Binder
<
'tcx
,
ty
::
TraitRef
<
'tcx
>>
,
ty
::
Binder
<
'tcx
,
ty
::
ExistentialTraitRef
<
'tcx
>>
,
ty
::
Binder
<
'tcx
,
TraitRefPrintOnlyTraitPath
<
'tcx
>>
,
ty
::
Binder
<
'tcx
,
TraitRefPrintOnlyTraitName
<
'tcx
>>
,
ty
::
Binder
<
'tcx
,
ty
::
FnSig
<
'tcx
>>
,
...
...
compiler/rustc_trait_selection/src/solve/trait_goals.rs
浏览文件 @
1bb6ae58
...
...
@@ -444,7 +444,7 @@ fn consider_builtin_unsize_candidates(
Err
(
NoSolution
)
=>
vec!
[],
};
ecx
.probe
(|
_
|
CandidateKind
::
DynUpcasting
Assembly
)
.enter
(|
ecx
|
{
ecx
.probe
(|
_
|
CandidateKind
::
Unsize
Assembly
)
.enter
(|
ecx
|
{
let
a_ty
=
goal
.predicate
.self_ty
();
// We need to normalize the b_ty since it's matched structurally
// in the other functions below.
...
...
@@ -526,7 +526,7 @@ fn consider_builtin_dyn_upcast_candidates(
b_region
:
ty
::
Region
<
'tcx
>
,
)
->
Vec
<
(
CanonicalResponse
<
'tcx
>
,
BuiltinImplSource
)
>
{
let
tcx
=
self
.tcx
();
let
Goal
{
predicate
:
(
a_ty
,
b_ty
),
..
}
=
goal
;
let
Goal
{
predicate
:
(
a_ty
,
_
b_ty
),
..
}
=
goal
;
// All of a's auto traits need to be in b's auto traits.
let
auto_traits_compatible
=
...
...
@@ -535,51 +535,30 @@ fn consider_builtin_dyn_upcast_candidates(
return
vec!
[];
}
// Try to match `a_ty` against `b_ty`, replacing `a_ty`'s principal trait ref with
// the supertrait principal and subtyping the types.
let
unsize_dyn_to_principal
=
|
ecx
:
&
mut
Self
,
principal
:
Option
<
ty
::
PolyExistentialTraitRef
<
'tcx
>>
|
{
ecx
.probe_candidate
(
"upcast dyn to principle"
)
.enter
(
|
ecx
|
->
Result
<
_
,
NoSolution
>
{
// Require that all of the trait predicates from A match B, except for
// the auto traits. We do this by constructing a new A type with B's
// auto traits, and equating these types.
let
new_a_data
=
principal
.into_iter
()
.map
(|
trait_ref
|
trait_ref
.map_bound
(
ty
::
ExistentialPredicate
::
Trait
))
.chain
(
a_data
.iter
()
.filter
(|
a
|
{
matches!
(
a
.skip_binder
(),
ty
::
ExistentialPredicate
::
Projection
(
_
))
}))
.chain
(
b_data
.auto_traits
()
.map
(
ty
::
ExistentialPredicate
::
AutoTrait
)
.map
(
ty
::
Binder
::
dummy
),
);
let
new_a_data
=
tcx
.mk_poly_existential_predicates_from_iter
(
new_a_data
);
let
new_a_ty
=
Ty
::
new_dynamic
(
tcx
,
new_a_data
,
b_region
,
ty
::
Dyn
);
// We also require that A's lifetime outlives B's lifetime.
ecx
.eq
(
goal
.param_env
,
new_a_ty
,
b_ty
)
?
;
ecx
.add_goal
(
goal
.with
(
tcx
,
ty
::
OutlivesPredicate
(
a_region
,
b_region
)));
ecx
.evaluate_added_goals_and_make_canonical_response
(
Certainty
::
Yes
)
},
)
};
let
mut
responses
=
vec!
[];
// If the principal def ids match (or are both none), then we're not doing
// trait upcasting. We're just removing auto traits (or shortening the lifetime).
if
a_data
.principal_def_id
()
==
b_data
.principal_def_id
()
{
if
let
Ok
(
resp
)
=
unsize_dyn_to_principal
(
self
,
a_data
.principal
())
{
if
let
Ok
(
resp
)
=
self
.consider_builtin_upcast_to_principal
(
goal
,
a_data
,
a_region
,
b_data
,
b_region
,
a_data
.principal
(),
)
{
responses
.push
((
resp
,
BuiltinImplSource
::
Misc
));
}
}
else
if
let
Some
(
a_principal
)
=
a_data
.principal
()
{
self
.walk_vtable
(
a_principal
.with_self_ty
(
tcx
,
a_ty
),
|
ecx
,
new_a_principal
,
_
,
vtable_vptr_slot
|
{
if
let
Ok
(
resp
)
=
unsize_dyn_to_principal
(
ecx
,
if
let
Ok
(
resp
)
=
ecx
.consider_builtin_upcast_to_principal
(
goal
,
a_data
,
a_region
,
b_data
,
b_region
,
Some
(
new_a_principal
.map_bound
(|
trait_ref
|
{
ty
::
ExistentialTraitRef
::
erase_self_ty
(
tcx
,
trait_ref
)
})),
...
...
@@ -631,6 +610,78 @@ fn consider_builtin_unsize_to_dyn(
self
.evaluate_added_goals_and_make_canonical_response
(
Certainty
::
Yes
)
}
fn
consider_builtin_upcast_to_principal
(
&
mut
self
,
goal
:
Goal
<
'tcx
,
(
Ty
<
'tcx
>
,
Ty
<
'tcx
>
)
>
,
a_data
:
&
'tcx
ty
::
List
<
ty
::
PolyExistentialPredicate
<
'tcx
>>
,
a_region
:
ty
::
Region
<
'tcx
>
,
b_data
:
&
'tcx
ty
::
List
<
ty
::
PolyExistentialPredicate
<
'tcx
>>
,
b_region
:
ty
::
Region
<
'tcx
>
,
upcast_principal
:
Option
<
ty
::
PolyExistentialTraitRef
<
'tcx
>>
,
)
->
QueryResult
<
'tcx
>
{
let
param_env
=
goal
.param_env
;
// More than one projection in a_ty's bounds may match the projection
// in b_ty's bound. Use this to first determine *which* apply without
// having any inference side-effects. We process obligations because
// unification may initially succeed due to deferred projection equality.
let
projection_may_match
=
|
ecx
:
&
mut
Self
,
source_projection
,
target_projection
|
{
ecx
.probe
(|
_
|
CandidateKind
::
UpcastProbe
)
.enter
(|
ecx
|
->
Result
<
(),
NoSolution
>
{
ecx
.eq
(
param_env
,
source_projection
,
target_projection
)
?
;
let
_
=
ecx
.try_evaluate_added_goals
()
?
;
Ok
(())
})
.is_ok
()
};
for
bound
in
b_data
{
match
bound
.skip_binder
()
{
// Check that a's supertrait (upcast_principal) is compatible
// with the target (b_ty).
ty
::
ExistentialPredicate
::
Trait
(
target_principal
)
=>
{
self
.eq
(
param_env
,
upcast_principal
.unwrap
(),
bound
.rebind
(
target_principal
))
?
;
}
// Check that b_ty's projection is satisfied by exactly one of
// a_ty's projections. First, we look through the list to see if
// any match. If not, error. Then, if *more* than one matches, we
// return ambiguity. Otherwise, if exactly one matches, equate
// it with b_ty's projection.
ty
::
ExistentialPredicate
::
Projection
(
target_projection
)
=>
{
let
target_projection
=
bound
.rebind
(
target_projection
);
let
mut
matching_projections
=
a_data
.projection_bounds
()
.filter
(|
source_projection
|
{
projection_may_match
(
self
,
*
source_projection
,
target_projection
)
});
let
Some
(
source_projection
)
=
matching_projections
.next
()
else
{
return
Err
(
NoSolution
);
};
if
matching_projections
.next
()
.is_some
()
{
return
self
.evaluate_added_goals_and_make_canonical_response
(
Certainty
::
AMBIGUOUS
,
);
}
self
.eq
(
param_env
,
source_projection
,
target_projection
)
?
;
}
// Check that b_ty's auto traits are present in a_ty's bounds.
ty
::
ExistentialPredicate
::
AutoTrait
(
def_id
)
=>
{
if
!
a_data
.auto_traits
()
.any
(|
source_def_id
|
source_def_id
==
def_id
)
{
return
Err
(
NoSolution
);
}
}
}
}
// Also require that a_ty's lifetime outlives b_ty's lifetime.
self
.add_goal
(
Goal
::
new
(
self
.tcx
(),
param_env
,
ty
::
Binder
::
dummy
(
ty
::
OutlivesPredicate
(
a_region
,
b_region
)),
));
self
.evaluate_added_goals_and_make_canonical_response
(
Certainty
::
Yes
)
}
/// We have the following builtin impls for arrays:
/// ```ignore (builtin impl example)
/// impl<T: ?Sized, const N: usize> Unsize<[T]> for [T; N] {}
...
...
compiler/rustc_trait_selection/src/traits/select/confirmation.rs
浏览文件 @
1bb6ae58
...
...
@@ -879,68 +879,89 @@ fn confirm_trait_upcasting_unsize_candidate(
// `assemble_candidates_for_unsizing` should ensure there are no late-bound
// regions here. See the comment there for more details.
let
source
=
self
.infcx
.shallow_resolve
(
obligation
.self_ty
()
.no_bound_vars
()
.unwrap
());
let
target
=
obligation
.predicate
.skip_binder
()
.trait_ref.args
.type_at
(
1
);
let
target
=
self
.infcx
.shallow_resolve
(
target
);
let
predicate
=
obligation
.predicate
.no_bound_vars
()
.unwrap
();
let
a_ty
=
self
.infcx
.shallow_resolve
(
predicate
.self_ty
());
let
b_ty
=
self
.infcx
.shallow_resolve
(
predicate
.trait_ref.args
.type_at
(
1
));
let
ty
::
Dynamic
(
a_data
,
a_region
,
ty
::
Dyn
)
=
*
a_ty
.kind
()
else
{
bug!
()
};
let
ty
::
Dynamic
(
b_data
,
b_region
,
ty
::
Dyn
)
=
*
b_ty
.kind
()
else
{
bug!
()
};
debug!
(
?
source
,
?
target
,
"confirm_trait_upcasting_unsize_candidate"
);
let
source_principal
=
a_data
.principal
()
.unwrap
()
.with_self_ty
(
tcx
,
a_ty
);
let
upcast_principal
=
util
::
supertraits
(
tcx
,
source_principal
)
.nth
(
idx
)
.unwrap
();
let
mut
nested
=
vec!
[];
let
source_trait_ref
;
let
upcast_trait_ref
;
match
(
source
.kind
(),
target
.kind
())
{
// TraitA+Kx+'a -> TraitB+Ky+'b (trait upcasting coercion).
(
&
ty
::
Dynamic
(
ref
data_a
,
r_a
,
repr_a
@
ty
::
Dyn
),
&
ty
::
Dynamic
(
ref
data_b
,
r_b
,
ty
::
Dyn
),
)
=>
{
// See `assemble_candidates_for_unsizing` for more info.
// We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`.
let
principal_a
=
data_a
.principal
()
.unwrap
();
source_trait_ref
=
principal_a
.with_self_ty
(
tcx
,
source
);
upcast_trait_ref
=
util
::
supertraits
(
tcx
,
source_trait_ref
)
.nth
(
idx
)
.unwrap
();
assert_eq!
(
data_b
.principal_def_id
(),
Some
(
upcast_trait_ref
.def_id
()));
let
existential_predicate
=
upcast_trait_ref
.map_bound
(|
trait_ref
|
{
ty
::
ExistentialPredicate
::
Trait
(
ty
::
ExistentialTraitRef
::
erase_self_ty
(
tcx
,
trait_ref
,
))
});
let
iter
=
Some
(
existential_predicate
)
.into_iter
()
.chain
(
data_a
.projection_bounds
()
.map
(|
b
|
b
.map_bound
(
ty
::
ExistentialPredicate
::
Projection
)),
)
.chain
(
data_b
.auto_traits
()
.map
(
ty
::
ExistentialPredicate
::
AutoTrait
)
.map
(
ty
::
Binder
::
dummy
),
for
bound
in
b_data
{
match
bound
.skip_binder
()
{
// Check that a's supertrait (upcast_principal) is compatible
// with the target (b_ty).
ty
::
ExistentialPredicate
::
Trait
(
target_principal
)
=>
{
nested
.extend
(
self
.infcx
.at
(
&
obligation
.cause
,
obligation
.param_env
)
.sup
(
DefineOpaqueTypes
::
No
,
upcast_principal
.map_bound
(|
trait_ref
|
{
ty
::
ExistentialTraitRef
::
erase_self_ty
(
tcx
,
trait_ref
)
}),
bound
.rebind
(
target_principal
),
)
.map_err
(|
_
|
SelectionError
::
Unimplemented
)
?
.into_obligations
(),
);
let
existential_predicates
=
tcx
.mk_poly_existential_predicates_from_iter
(
iter
);
let
source_trait
=
Ty
::
new_dynamic
(
tcx
,
existential_predicates
,
r_b
,
repr_a
);
// Require that the traits involved in this upcast are **equal**;
// only the **lifetime bound** is changed.
let
InferOk
{
obligations
,
..
}
=
self
.infcx
.at
(
&
obligation
.cause
,
obligation
.param_env
)
.sup
(
DefineOpaqueTypes
::
No
,
target
,
source_trait
)
.map_err
(|
_
|
Unimplemented
)
?
;
nested
.extend
(
obligations
);
let
outlives
=
ty
::
OutlivesPredicate
(
r_a
,
r_b
);
nested
.push
(
Obligation
::
with_depth
(
tcx
,
obligation
.cause
.clone
(),
obligation
.recursion_depth
+
1
,
obligation
.param_env
,
obligation
.predicate
.rebind
(
outlives
),
));
}
// Check that b_ty's projection is satisfied by exactly one of
// a_ty's projections. First, we look through the list to see if
// any match. If not, error. Then, if *more* than one matches, we
// return ambiguity. Otherwise, if exactly one matches, equate
// it with b_ty's projection.
ty
::
ExistentialPredicate
::
Projection
(
target_projection
)
=>
{
let
target_projection
=
bound
.rebind
(
target_projection
);
let
mut
matching_projections
=
a_data
.projection_bounds
()
.filter
(|
source_projection
|
{
// Eager normalization means that we can just use can_eq
// here instead of equating and processing obligations.
self
.infcx
.can_eq
(
obligation
.param_env
,
*
source_projection
,
target_projection
,
)
});
let
Some
(
source_projection
)
=
matching_projections
.next
()
else
{
return
Err
(
SelectionError
::
Unimplemented
);
};
if
matching_projections
.next
()
.is_some
()
{
// This is incomplete but I don't care. We should never
// have more than one projection that ever applies with
// eager norm and actually implementable traits, since
// you can't have two supertraits like:
// `trait A: B<i32, Assoc = First> + B<i32, Assoc = Second>`
return
Err
(
SelectionError
::
Unimplemented
);
}
nested
.extend
(
self
.infcx
.at
(
&
obligation
.cause
,
obligation
.param_env
)
.sup
(
DefineOpaqueTypes
::
No
,
source_projection
,
target_projection
)
.map_err
(|
_
|
SelectionError
::
Unimplemented
)
?
.into_obligations
(),
);
}
// Check that b_ty's auto trait is present in a_ty's bounds.
ty
::
ExistentialPredicate
::
AutoTrait
(
def_id
)
=>
{
if
!
a_data
.auto_traits
()
.any
(|
source_def_id
|
source_def_id
==
def_id
)
{
return
Err
(
SelectionError
::
Unimplemented
);
}
}
}
_
=>
bug!
(),
};
}
// Also require that a_ty's lifetime outlives b_ty's lifetime.
nested
.push
(
Obligation
::
with_depth
(
tcx
,
obligation
.cause
.clone
(),
obligation
.recursion_depth
+
1
,
obligation
.param_env
,
ty
::
Binder
::
dummy
(
ty
::
OutlivesPredicate
(
a_region
,
b_region
)),
));
let
vtable_segment_callback
=
{
let
mut
vptr_offset
=
0
;
...
...
@@ -951,7 +972,7 @@ fn confirm_trait_upcasting_unsize_candidate(
}
VtblSegment
::
TraitOwnEntries
{
trait_ref
,
emit_vptr
}
=>
{
vptr_offset
+=
count_own_vtable_entries
(
tcx
,
trait_ref
);
if
trait_ref
==
upcast_
trait_ref
{
if
trait_ref
==
upcast_
principal
{
if
emit_vptr
{
return
ControlFlow
::
Break
(
Some
(
vptr_offset
));
}
else
{
...
...
@@ -969,7 +990,7 @@ fn confirm_trait_upcasting_unsize_candidate(
};
let
vtable_vptr_slot
=
prepare_vtable_segments
(
tcx
,
source_
trait_ref
,
vtable_segment_callback
)
.unwrap
();
prepare_vtable_segments
(
tcx
,
source_
principal
,
vtable_segment_callback
)
.unwrap
();
Ok
(
ImplSource
::
Builtin
(
BuiltinImplSource
::
TraitUpcasting
{
vtable_vptr_slot
},
nested
))
}
...
...
tests/ui/traits/trait-upcasting/fewer-associated.rs
0 → 100644
浏览文件 @
1bb6ae58
// check-pass
// issue: 114035
// revisions: current next
//[next] compile-flags: -Ztrait-solver=next
#![feature(trait_upcasting)]
trait
A
:
B
{
type
Assoc
;
}
trait
B
{}
fn
upcast
(
a
:
&
dyn
A
<
Assoc
=
i32
>
)
->
&
dyn
B
{
a
}
// Make sure that we can drop the existential projection `A::Assoc = i32`
// when upcasting `dyn A<Assoc = i32>` to `dyn B`. Before, we used some
// complicated algorithm which required rebuilding a new object type with
// different bounds in order to test that an upcast was valid, but this
// didn't allow upcasting to t that have fewer associated types
// than the source type.
fn
main
()
{}
tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr
0 → 100644
浏览文件 @
1bb6ae58
error[E0308]: mismatched types
--> $DIR/illegal-upcast-from-impl.rs:16:66
|
LL | fn illegal(x: &dyn Sub<Assoc = ()>) -> &dyn Super<Assoc = i32> { x }
| ----------------------- ^ expected trait `Super`, found trait `Sub`
| |
| expected `&dyn Super<Assoc = i32>` because of return type
|
= note: expected reference `&dyn Super<Assoc = i32>`
found reference `&dyn Sub<Assoc = ()>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.
tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr
0 → 100644
浏览文件 @
1bb6ae58
error[E0308]: mismatched types
--> $DIR/illegal-upcast-from-impl.rs:16:66
|
LL | fn illegal(x: &dyn Sub<Assoc = ()>) -> &dyn Super<Assoc = i32> { x }
| ----------------------- ^ expected trait `Super`, found trait `Sub`
| |
| expected `&dyn Super<Assoc = i32>` because of return type
|
= note: expected reference `&dyn Super<Assoc = i32>`
found reference `&dyn Sub<Assoc = ()>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.
tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs
0 → 100644
浏览文件 @
1bb6ae58
// revisions: current next
//[next] compile-flags: -Ztrait-solver=next
#![feature(trait_upcasting)]
trait
Super
{
type
Assoc
;
}
trait
Sub
:
Super
{}
impl
<
T
:
?
Sized
>
Super
for
T
{
type
Assoc
=
i32
;
}
fn
illegal
(
x
:
&
dyn
Sub
<
Assoc
=
()
>
)
->
&
dyn
Super
<
Assoc
=
i32
>
{
x
}
//~^ ERROR mismatched types
// Want to make sure that we can't "upcast" to a supertrait that has a different
// associated type that is instead provided by a blanket impl (and doesn't come
// from the object bounds).
fn
main
()
{}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录