Skip to content

Commit ea38a59

Browse files
committed
Fix regression in fix for #1173
A regression was introduced in e476433c45624ec713395c85bcbd410806e90639 this was a tricky bug to fix. There are several fixes here but they all rely on one another so in order to have a commit which does not introduce more regressions it seems best to keep these fixes together. In this patch we remove the check at the end of type resolution to look for any error type nodes within the type context since this will only ever produce false postive/duplicate errors. Since any real error will have been emitted at the time of occurance. We also fixed a bug in infering the types on a generic type so for example: struct Foo<A,B>(A,B); impl<T> Foo<T,T> { ... } In this example the Self type on the impl block will be Foo<T,T> so in the code for infering the arguments for the type we simply iterated each of the generic parameter mappings and if any of them need substitution we generate implict inference variables for them but in this case the ParamType is T so generating one for each of these T's will introduce a stay inference variable which we cannot infer so it will not be used. This patch keeps a mapping inside SubstitutionRef::infer_substitions to ensure we don't introduce any extra inference variables than required. The final fix was around how we clone inference variables, there is a comment explaining this but we cannot safely clone a inference variables simply by creating a new object, inference variables are closely tied to the type-conext so that when we infer the type to be a concrete type we need to be able to update the reference in memory but simply cloning an inference variable does not guarentee this to occur. This change ensures that we create a new implict inference variable and setup the reference and chain apropirately.
1 parent 40f2979 commit ea38a59

File tree

8 files changed

+76
-102
lines changed

8 files changed

+76
-102
lines changed

gcc/rust/hir/tree/rust-hir-path.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ class PathPattern : public Pattern
262262

263263
std::vector<PathExprSegment> &get_segments () { return segments; }
264264

265+
const std::vector<PathExprSegment> &get_segments () const { return segments; }
266+
265267
PathExprSegment &get_root_seg () { return segments.at (0); }
266268

267269
PathExprSegment get_final_segment () const { return segments.back (); }

gcc/rust/typecheck/rust-hir-type-check-expr.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -221,13 +221,6 @@ class TypeCheckExpr : public TypeCheckBase
221221

222222
infered
223223
= TyTy::TypeCheckCallExpr::go (function_tyty, expr, variant, context);
224-
if (infered == nullptr)
225-
{
226-
rust_error_at (expr.get_locus (), "failed to lookup type to CallExpr");
227-
return;
228-
}
229-
230-
infered->set_ref (expr.get_mappings ().get_hirid ());
231224
}
232225

233226
void visit (HIR::MethodCallExpr &expr) override
@@ -1076,7 +1069,6 @@ class TypeCheckExpr : public TypeCheckBase
10761069
: TypeCheckBase (), infered (nullptr), inside_loop (inside_loop)
10771070
{}
10781071

1079-
// Beware: currently returns Tyty::ErrorType or nullptr in case of error.
10801072
TyTy::BaseType *resolve_root_path (HIR::PathInExpression &expr,
10811073
size_t *offset,
10821074
NodeId *root_resolved_node_id);

gcc/rust/typecheck/rust-hir-type-check-path.cc

Lines changed: 25 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -138,27 +138,17 @@ void
138138
TypeCheckExpr::visit (HIR::PathInExpression &expr)
139139
{
140140
NodeId resolved_node_id = UNKNOWN_NODEID;
141-
142141
size_t offset = -1;
143142
TyTy::BaseType *tyseg = resolve_root_path (expr, &offset, &resolved_node_id);
144-
rust_assert (tyseg != nullptr);
145-
146143
if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
147144
return;
148145

149-
if (expr.get_num_segments () == 1)
150-
{
151-
Location locus = expr.get_segments ().back ().get_locus ();
152-
153-
bool is_big_self
154-
= expr.get_segments ().front ().get_segment ().as_string ().compare (
155-
"Self")
156-
== 0;
157-
if (!is_big_self && tyseg->needs_generic_substitutions ())
158-
{
159-
tyseg = SubstMapper::InferSubst (tyseg, locus);
160-
}
146+
if (tyseg->needs_generic_substitutions ())
147+
tyseg = SubstMapper::InferSubst (tyseg, expr.get_locus ());
161148

149+
bool fully_resolved = offset == expr.get_segments ().size ();
150+
if (fully_resolved)
151+
{
162152
infered = tyseg;
163153
return;
164154
}
@@ -171,14 +161,11 @@ TyTy::BaseType *
171161
TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset,
172162
NodeId *root_resolved_node_id)
173163
{
174-
TyTy::BaseType *root_tyty = nullptr;
175164
*offset = 0;
176165
for (size_t i = 0; i < expr.get_num_segments (); i++)
177166
{
178167
HIR::PathExprSegment &seg = expr.get_segments ().at (i);
179-
180168
bool have_more_segments = (expr.get_num_segments () - 1 != i);
181-
bool is_root = *offset == 0 || root_tyty == nullptr;
182169
NodeId ast_node_id = seg.get_mappings ().get_nodeid ();
183170

184171
// then lookup the reference_node_id
@@ -205,40 +192,30 @@ TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset,
205192
// ref_node_id is the NodeId that the segments refers to.
206193
if (ref_node_id == UNKNOWN_NODEID)
207194
{
208-
if (is_root)
209-
{
210-
rust_error_at (seg.get_locus (),
211-
"failed to type resolve root segment");
212-
return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
213-
}
214-
return root_tyty;
195+
rust_error_at (seg.get_locus (),
196+
"failed to type resolve root segment");
197+
return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
215198
}
216199

217200
// node back to HIR
218201
HirId ref;
219202
if (!mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (),
220203
ref_node_id, &ref))
221204
{
222-
if (is_root)
223-
{
224-
rust_error_at (seg.get_locus (), "456 reverse lookup failure");
225-
rust_debug_loc (
226-
seg.get_locus (),
227-
"failure with [%s] mappings [%s] ref_node_id [%u]",
228-
seg.as_string ().c_str (),
229-
seg.get_mappings ().as_string ().c_str (), ref_node_id);
205+
rust_error_at (seg.get_locus (), "456 reverse lookup failure");
206+
rust_debug_loc (seg.get_locus (),
207+
"failure with [%s] mappings [%s] ref_node_id [%u]",
208+
seg.as_string ().c_str (),
209+
seg.get_mappings ().as_string ().c_str (),
210+
ref_node_id);
230211

231-
return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
232-
}
233-
234-
return root_tyty;
212+
return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
235213
}
236214

237215
auto seg_is_module
238216
= (nullptr
239217
!= mappings->lookup_module (expr.get_mappings ().get_crate_num (),
240218
ref));
241-
242219
if (seg_is_module)
243220
{
244221
// A::B::C::this_is_a_module::D::E::F
@@ -261,33 +238,8 @@ TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset,
261238
TyTy::BaseType *lookup = nullptr;
262239
if (!context->lookup_type (ref, &lookup))
263240
{
264-
if (is_root)
265-
{
266-
rust_error_at (seg.get_locus (),
267-
"failed to resolve root segment");
268-
return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
269-
}
270-
return root_tyty;
271-
}
272-
273-
// if we have a previous segment type
274-
if (root_tyty != nullptr)
275-
{
276-
// if this next segment needs substitution we must apply the
277-
// previous type arguments
278-
//
279-
// such as: GenericStruct::<_>::new(123, 456)
280-
if (lookup->needs_generic_substitutions ())
281-
{
282-
if (!root_tyty->needs_generic_substitutions ())
283-
{
284-
auto used_args_in_prev_segment
285-
= GetUsedSubstArgs::From (root_tyty);
286-
lookup
287-
= SubstMapperInternal::Resolve (lookup,
288-
used_args_in_prev_segment);
289-
}
290-
}
241+
rust_error_at (seg.get_locus (), "failed to resolve root segment");
242+
return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
291243
}
292244

293245
// turbo-fish segment path::<ty>
@@ -300,16 +252,16 @@ TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset,
300252
lookup->as_string ().c_str ());
301253
return new TyTy::ErrorType (lookup->get_ref ());
302254
}
303-
lookup = SubstMapper::Resolve (lookup, expr.get_locus (),
255+
lookup = SubstMapper::Resolve (lookup, seg.get_locus (),
304256
&seg.get_generic_args ());
305257
}
306258

307259
*root_resolved_node_id = ref_node_id;
308260
*offset = *offset + 1;
309-
root_tyty = lookup;
261+
return lookup;
310262
}
311263

312-
return root_tyty;
264+
return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
313265
}
314266

315267
void
@@ -424,19 +376,11 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id,
424376
bool ok = context->lookup_type (impl_ty_id, &impl_block_ty);
425377
rust_assert (ok);
426378

427-
if (prev_segment->needs_generic_substitutions ())
428-
{
429-
if (!impl_block_ty->needs_generic_substitutions ())
430-
{
431-
prev_segment = impl_block_ty;
432-
}
433-
else
434-
{
435-
HIR::PathExprSegment &pseg = segments.at (i - 1);
436-
Location locus = pseg.get_locus ();
437-
prev_segment = SubstMapper::InferSubst (prev_segment, locus);
438-
}
439-
}
379+
if (impl_block_ty->needs_generic_substitutions ())
380+
impl_block_ty
381+
= SubstMapper::InferSubst (impl_block_ty, seg.get_locus ());
382+
383+
prev_segment = prev_segment->unify (impl_block_ty);
440384
}
441385

442386
if (tyseg->needs_generic_substitutions ())

gcc/rust/typecheck/rust-hir-type-check.cc

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,11 @@ TypeResolution::Resolve (HIR::Crate &crate)
5454

5555
// default inference variables if possible
5656
context->iterate ([&] (HirId id, TyTy::BaseType *ty) mutable -> bool {
57-
if (ty->get_kind () == TyTy::TypeKind::ERROR)
58-
{
59-
rust_error_at (mappings->lookup_location (id),
60-
"failure in type resolution for %u", id);
61-
return false;
62-
}
63-
6457
// nothing to do
6558
if (ty->get_kind () != TyTy::TypeKind::INFER)
6659
return true;
6760

68-
TyTy::InferType *infer_var = (TyTy::InferType *) ty;
61+
TyTy::InferType *infer_var = static_cast<TyTy::InferType *> (ty);
6962
TyTy::BaseType *default_type;
7063
bool ok = infer_var->default_type (&default_type);
7164
if (!ok)

gcc/rust/typecheck/rust-tyty-rules.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ class BaseRules : public TyVisitor
8989
for (auto ref : other->get_combined_refs ())
9090
resolved->append_reference (ref);
9191

92+
other->append_reference (resolved->get_ref ());
93+
other->append_reference (get_base ()->get_ref ());
94+
get_base ()->append_reference (resolved->get_ref ());
95+
get_base ()->append_reference (other->get_ref ());
96+
9297
bool result_resolved = resolved->get_kind () != TyTy::TypeKind::INFER;
9398
bool result_is_infer_var = resolved->get_kind () == TyTy::TypeKind::INFER;
9499
bool results_is_non_general_infer_var

gcc/rust/typecheck/rust-tyty.cc

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ TyVar::get_implicit_infer_var (Location locus)
263263
infer);
264264
mappings->insert_location (mappings->get_current_crate (), infer->get_ref (),
265265
locus);
266+
266267
return TyVar (infer->get_ref ());
267268
}
268269

@@ -341,8 +342,34 @@ InferType::cast (BaseType *other)
341342
BaseType *
342343
InferType::clone () const
343344
{
344-
return new InferType (get_ref (), get_ty_ref (), get_infer_kind (),
345-
get_ident ().locus, get_combined_refs ());
345+
// clones for inference variables are special in that they _must_ exist within
346+
// the type check context and we must ensure we don't loose the chain
347+
// otherwise we will end up in the missing type annotations case
348+
//
349+
// This means we cannot simply take over the same reference we must generate a
350+
// new ref just like the get_implicit_infer_var code then we can setup the
351+
// chain of references accordingly to ensure we don't loose the ability to
352+
// update the inference variables when we solve the type
353+
354+
auto mappings = Analysis::Mappings::get ();
355+
auto context = Resolver::TypeCheckContext::get ();
356+
357+
InferType *clone
358+
= new InferType (mappings->get_next_hir_id (), get_infer_kind (),
359+
get_ident ().locus, get_combined_refs ());
360+
361+
context->insert_type (Analysis::NodeMapping (mappings->get_current_crate (),
362+
UNKNOWN_NODEID,
363+
clone->get_ref (),
364+
UNKNOWN_LOCAL_DEFID),
365+
clone);
366+
mappings->insert_location (mappings->get_current_crate (), clone->get_ref (),
367+
mappings->lookup_location (get_ref ()));
368+
369+
// setup the chain to reference this
370+
clone->append_reference (get_ref ());
371+
372+
return clone;
346373
}
347374

348375
bool

gcc/rust/typecheck/rust-tyty.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -955,12 +955,23 @@ class SubstitutionRef
955955
BaseType *infer_substitions (Location locus)
956956
{
957957
std::vector<SubstitutionArg> args;
958+
std::map<std::string, BaseType *> argument_mappings;
958959
for (auto &p : get_substs ())
959960
{
960961
if (p.needs_substitution ())
961962
{
962-
TyVar infer_var = TyVar::get_implicit_infer_var (locus);
963-
args.push_back (SubstitutionArg (&p, infer_var.get_tyty ()));
963+
const std::string &symbol = p.get_param_ty ()->get_symbol ();
964+
auto it = argument_mappings.find (symbol);
965+
if (it == argument_mappings.end ())
966+
{
967+
TyVar infer_var = TyVar::get_implicit_infer_var (locus);
968+
args.push_back (SubstitutionArg (&p, infer_var.get_tyty ()));
969+
argument_mappings[symbol] = infer_var.get_tyty ();
970+
}
971+
else
972+
{
973+
args.push_back (SubstitutionArg (&p, it->second));
974+
}
964975
}
965976
else
966977
{

gcc/testsuite/rust/compile/torture/issue-893-2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ impl Baz<i32, f32> {
2424

2525
pub fn main() {
2626
let a = Foo::<i32>::new::<f32>(123, 456f32);
27-
// let b = Foo::new::<f32>(123, 456f32);
27+
let b = Foo::new::<f32>(123, 456f32);
2828

2929
let c = Bar::<i32>(123);
3030
let d = Bar::baz(c);

0 commit comments

Comments
 (0)