diff options
Diffstat (limited to 'crates/ra_hir_ty/src/lower.rs')
-rw-r--r-- | crates/ra_hir_ty/src/lower.rs | 70 |
1 files changed, 46 insertions, 24 deletions
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index a05cbd7fc..42713928f 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs | |||
@@ -323,6 +323,7 @@ impl Ty { | |||
323 | resolution: TypeNs, | 323 | resolution: TypeNs, |
324 | resolved_segment: PathSegment<'_>, | 324 | resolved_segment: PathSegment<'_>, |
325 | remaining_segments: PathSegments<'_>, | 325 | remaining_segments: PathSegments<'_>, |
326 | infer_args: bool, | ||
326 | ) -> (Ty, Option<TypeNs>) { | 327 | ) -> (Ty, Option<TypeNs>) { |
327 | let ty = match resolution { | 328 | let ty = match resolution { |
328 | TypeNs::TraitId(trait_) => { | 329 | TypeNs::TraitId(trait_) => { |
@@ -400,9 +401,15 @@ impl Ty { | |||
400 | ctx.db.ty(adt.into()).subst(&substs) | 401 | ctx.db.ty(adt.into()).subst(&substs) |
401 | } | 402 | } |
402 | 403 | ||
403 | TypeNs::AdtId(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), | 404 | TypeNs::AdtId(it) => { |
404 | TypeNs::BuiltinType(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), | 405 | Ty::from_hir_path_inner(ctx, resolved_segment, it.into(), infer_args) |
405 | TypeNs::TypeAliasId(it) => Ty::from_hir_path_inner(ctx, resolved_segment, it.into()), | 406 | } |
407 | TypeNs::BuiltinType(it) => { | ||
408 | Ty::from_hir_path_inner(ctx, resolved_segment, it.into(), infer_args) | ||
409 | } | ||
410 | TypeNs::TypeAliasId(it) => { | ||
411 | Ty::from_hir_path_inner(ctx, resolved_segment, it.into(), infer_args) | ||
412 | } | ||
406 | // FIXME: report error | 413 | // FIXME: report error |
407 | TypeNs::EnumVariantId(_) => return (Ty::Unknown, None), | 414 | TypeNs::EnumVariantId(_) => return (Ty::Unknown, None), |
408 | }; | 415 | }; |
@@ -428,7 +435,13 @@ impl Ty { | |||
428 | ), | 435 | ), |
429 | Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)), | 436 | Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)), |
430 | }; | 437 | }; |
431 | Ty::from_partly_resolved_hir_path(ctx, resolution, resolved_segment, remaining_segments) | 438 | Ty::from_partly_resolved_hir_path( |
439 | ctx, | ||
440 | resolution, | ||
441 | resolved_segment, | ||
442 | remaining_segments, | ||
443 | false, | ||
444 | ) | ||
432 | } | 445 | } |
433 | 446 | ||
434 | fn select_associated_type( | 447 | fn select_associated_type( |
@@ -474,13 +487,14 @@ impl Ty { | |||
474 | ctx: &TyLoweringContext<'_>, | 487 | ctx: &TyLoweringContext<'_>, |
475 | segment: PathSegment<'_>, | 488 | segment: PathSegment<'_>, |
476 | typable: TyDefId, | 489 | typable: TyDefId, |
490 | infer_args: bool, | ||
477 | ) -> Ty { | 491 | ) -> Ty { |
478 | let generic_def = match typable { | 492 | let generic_def = match typable { |
479 | TyDefId::BuiltinType(_) => None, | 493 | TyDefId::BuiltinType(_) => None, |
480 | TyDefId::AdtId(it) => Some(it.into()), | 494 | TyDefId::AdtId(it) => Some(it.into()), |
481 | TyDefId::TypeAliasId(it) => Some(it.into()), | 495 | TyDefId::TypeAliasId(it) => Some(it.into()), |
482 | }; | 496 | }; |
483 | let substs = substs_from_path_segment(ctx, segment, generic_def, false); | 497 | let substs = substs_from_path_segment(ctx, segment, generic_def, infer_args); |
484 | ctx.db.ty(typable).subst(&substs) | 498 | ctx.db.ty(typable).subst(&substs) |
485 | } | 499 | } |
486 | 500 | ||
@@ -493,6 +507,7 @@ impl Ty { | |||
493 | // `ValueTyDefId` is just a convenient way to pass generics and | 507 | // `ValueTyDefId` is just a convenient way to pass generics and |
494 | // special-case enum variants | 508 | // special-case enum variants |
495 | resolved: ValueTyDefId, | 509 | resolved: ValueTyDefId, |
510 | infer_args: bool, | ||
496 | ) -> Substs { | 511 | ) -> Substs { |
497 | let last = path.segments().last().expect("path should have at least one segment"); | 512 | let last = path.segments().last().expect("path should have at least one segment"); |
498 | let (segment, generic_def) = match resolved { | 513 | let (segment, generic_def) = match resolved { |
@@ -515,22 +530,27 @@ impl Ty { | |||
515 | (segment, Some(var.parent.into())) | 530 | (segment, Some(var.parent.into())) |
516 | } | 531 | } |
517 | }; | 532 | }; |
518 | substs_from_path_segment(ctx, segment, generic_def, false) | 533 | substs_from_path_segment(ctx, segment, generic_def, infer_args) |
519 | } | 534 | } |
520 | } | 535 | } |
521 | 536 | ||
522 | pub(super) fn substs_from_path_segment( | 537 | fn substs_from_path_segment( |
523 | ctx: &TyLoweringContext<'_>, | 538 | ctx: &TyLoweringContext<'_>, |
524 | segment: PathSegment<'_>, | 539 | segment: PathSegment<'_>, |
525 | def_generic: Option<GenericDefId>, | 540 | def_generic: Option<GenericDefId>, |
526 | _add_self_param: bool, | 541 | infer_args: bool, |
527 | ) -> Substs { | 542 | ) -> Substs { |
528 | let mut substs = Vec::new(); | 543 | let mut substs = Vec::new(); |
529 | let def_generics = def_generic.map(|def| generics(ctx.db.upcast(), def)); | 544 | let def_generics = def_generic.map(|def| generics(ctx.db.upcast(), def)); |
530 | 545 | ||
531 | let (parent_params, self_params, type_params, impl_trait_params) = | 546 | let (parent_params, self_params, type_params, impl_trait_params) = |
532 | def_generics.map_or((0, 0, 0, 0), |g| g.provenance_split()); | 547 | def_generics.map_or((0, 0, 0, 0), |g| g.provenance_split()); |
548 | let total_len = parent_params + self_params + type_params + impl_trait_params; | ||
549 | |||
533 | substs.extend(iter::repeat(Ty::Unknown).take(parent_params)); | 550 | substs.extend(iter::repeat(Ty::Unknown).take(parent_params)); |
551 | |||
552 | let mut had_explicit_args = false; | ||
553 | |||
534 | if let Some(generic_args) = &segment.args_and_bindings { | 554 | if let Some(generic_args) = &segment.args_and_bindings { |
535 | if !generic_args.has_self_type { | 555 | if !generic_args.has_self_type { |
536 | substs.extend(iter::repeat(Ty::Unknown).take(self_params)); | 556 | substs.extend(iter::repeat(Ty::Unknown).take(self_params)); |
@@ -542,31 +562,35 @@ pub(super) fn substs_from_path_segment( | |||
542 | for arg in generic_args.args.iter().skip(skip).take(expected_num) { | 562 | for arg in generic_args.args.iter().skip(skip).take(expected_num) { |
543 | match arg { | 563 | match arg { |
544 | GenericArg::Type(type_ref) => { | 564 | GenericArg::Type(type_ref) => { |
565 | had_explicit_args = true; | ||
545 | let ty = Ty::from_hir(ctx, type_ref); | 566 | let ty = Ty::from_hir(ctx, type_ref); |
546 | substs.push(ty); | 567 | substs.push(ty); |
547 | } | 568 | } |
548 | } | 569 | } |
549 | } | 570 | } |
550 | } | 571 | } |
551 | let total_len = parent_params + self_params + type_params + impl_trait_params; | ||
552 | // add placeholders for args that were not provided | ||
553 | for _ in substs.len()..total_len { | ||
554 | substs.push(Ty::Unknown); | ||
555 | } | ||
556 | assert_eq!(substs.len(), total_len); | ||
557 | 572 | ||
558 | // handle defaults | 573 | // handle defaults. In expression or pattern path segments without |
559 | if let Some(def_generic) = def_generic { | 574 | // explicitly specified type arguments, missing type arguments are inferred |
560 | let default_substs = ctx.db.generic_defaults(def_generic); | 575 | // (i.e. defaults aren't used). |
561 | assert_eq!(substs.len(), default_substs.len()); | 576 | if !infer_args || had_explicit_args { |
577 | if let Some(def_generic) = def_generic { | ||
578 | let default_substs = ctx.db.generic_defaults(def_generic); | ||
579 | assert_eq!(total_len, default_substs.len()); | ||
562 | 580 | ||
563 | for (i, default_ty) in default_substs.iter().enumerate() { | 581 | for default_ty in default_substs.iter().skip(substs.len()) { |
564 | if substs[i] == Ty::Unknown { | 582 | substs.push(default_ty.clone()); |
565 | substs[i] = default_ty.clone(); | ||
566 | } | 583 | } |
567 | } | 584 | } |
568 | } | 585 | } |
569 | 586 | ||
587 | // add placeholders for args that were not provided | ||
588 | // FIXME: emit diagnostics in contexts where this is not allowed | ||
589 | for _ in substs.len()..total_len { | ||
590 | substs.push(Ty::Unknown); | ||
591 | } | ||
592 | assert_eq!(substs.len(), total_len); | ||
593 | |||
570 | Substs(substs.into()) | 594 | Substs(substs.into()) |
571 | } | 595 | } |
572 | 596 | ||
@@ -615,9 +639,7 @@ impl TraitRef { | |||
615 | segment: PathSegment<'_>, | 639 | segment: PathSegment<'_>, |
616 | resolved: TraitId, | 640 | resolved: TraitId, |
617 | ) -> Substs { | 641 | ) -> Substs { |
618 | let has_self_param = | 642 | substs_from_path_segment(ctx, segment, Some(resolved.into()), false) |
619 | segment.args_and_bindings.as_ref().map(|a| a.has_self_type).unwrap_or(false); | ||
620 | substs_from_path_segment(ctx, segment, Some(resolved.into()), !has_self_param) | ||
621 | } | 643 | } |
622 | 644 | ||
623 | pub(crate) fn from_type_bound( | 645 | pub(crate) fn from_type_bound( |