---
title: Underlying type inference for opaque result types (OpaqueTypeInference)
framework: swift-compiler
role: article
role_heading: Article
path: swift-compiler/documentation/diagnostics/opaque-type-inference
---

# Underlying type inference for opaque result types (OpaqueTypeInference)

## Overview

Overview Opaque result types are a useful tool for abstracting the return type of a function or subscript, or type of a property. Although the concrete underlying type of an opaque type is hidden from clients, it is still inferred by the compiler, which enforces certain usage requirements: Property declarations with opaque types must have an initializer expression or getter, and functions or subscripts returning opaque types must have at least one return statement: let x: some Equatable // error: property declares an opaque return type, but has no initializer expression from which to infer an underlying type let y: some Equatable = 42 // OK let z: some Equatable { // Also OK   return "hello, " + "world!" }

func foo() -> some Equatable { // error: function declares an opaque return type, but has no return statements in its body from which to infer an underlying type   fatalError("Unimplemented") }

func bar() -> some Equatable { // OK   fatalError("Unimplemented")   return 42 } The underlying type of an opaque type must be unique. In other words, if a function or subscript returns an opaque type, it must return values of the same underlying type from every return statement in its body. func foo(bar: Bool) -> some Equatable { // error: function declares an opaque return type, but the return statements in its body do not have matching underlying types   if bar {     return "hello, world!" // note: return statement has underlying type 'String'   } else {     return 1 // note: return statement has underlying type 'Int'   } }

func bar(baz: Bool) -> some Equatable { // OK, both branches of the if statement return a value of the same underlying type, Int.   if baz {     return 100   } else {     return 200   } } Functions returning opaque types may be recursive. However, such functions must have at least one return statement that returns a concrete underlying type as opposed to the function’s own opaque result type. Additionally, recursive calls may not be used to create an infinitely recursive opaque type. func foo(_ x: Int) -> some Equatable { // error: function declares an opaque return type, but has no return statements in its body from which to infer an underlying type   // Not allowed because there aren't any non-recursive returns to infer the underlying type from.   return foo(x+1) }

struct EquatableWrapper<T: Equatable>: Equatable { var value: T } func foo() -> some Equatable { // error: function opaque return type was inferred as 'EquatableWrapper<some Equatable>', which defines the opaque type in terms of itself   // Not allowed because the use of EquatableWrapper creates an infinitely recursive underlying type: EquatableWrapper<EquatableWrapper<EquatableWrapper<...>>>...>   return EquatableWrapper(value: foo()) }

func bar(_ x: Int) -> some Equatable { // OK, the underlying type can be inferred from the second return statement.   if x > 0 {     return bar(x-1)   } else {     return x   } } To learn more about opaque result types, see the Opaque Types section of The Swift Programming Language.

## See Also

### Related Documentation

- [Opaque Types](swift-compiler/documentation/swift-book/documentation/the-swift-programming-language/opaquetypes.md)

- [@dynamicCallable implementation requirements (DynamicCallable)](swift-compiler/documentation/diagnostics/dynamic-callable-requirements.md)
- [Add @preconcurrency import (AddPreconcurrencyImport)](swift-compiler/documentation/diagnostics/add-preconcurrency-import.md)
- [Always enabled availability domains (AlwaysAvailableDomain)](swift-compiler/documentation/diagnostics/always-available-domain.md)
- [Argument matching for trailing closures (TrailingClosureMatching)](swift-compiler/documentation/diagnostics/trailing-closure-matching.md)
- [Calling a mutating async actor-isolated method (ActorIsolatedMutatingAsync)](swift-compiler/documentation/diagnostics/actor-isolated-mutating-async.md)
- [Calling an actor-isolated method from a synchronous nonisolated context (ActorIsolatedCall)](swift-compiler/documentation/diagnostics/actor-isolated-call.md)
- [Captures in a `@Sendable` closure (SendableClosureCaptures)](swift-compiler/documentation/diagnostics/sendable-closure-captures.md)
- [Compilation caching (CompilationCaching)](swift-compiler/documentation/diagnostics/compilation-caching.md)
- [Conforming to `StringInterpolationProtocol` (StringInterpolationConformance)](swift-compiler/documentation/diagnostics/string-interpolation-conformance.md)
- [Conversion from `@isolated(any)` function type to synchronous function type (ConversionFromIsolatedAnyToSynchronous)](swift-compiler/documentation/diagnostics/conversion-from-isolated-any-to-synchronous.md)
- [Cross-isolation data race (RegionIsolationCrossIsolationDataRace)](swift-compiler/documentation/diagnostics/region-isolation-cross-isolation-data-race.md)
- [Deprecated declaration warnings (DeprecatedDeclaration)](swift-compiler/documentation/diagnostics/deprecated-declaration.md)
- [Deprecated implementation-only imports (ImplementationOnlyDeprecated)](swift-compiler/documentation/diagnostics/implementation-only-deprecated.md)
- [Dynamic exclusivity (DynamicExclusivity)](swift-compiler/documentation/diagnostics/dynamic-exclusivity.md)
- [Embedded Swift language restrictions (EmbeddedRestrictions)](swift-compiler/documentation/diagnostics/embedded-restrictions.md)
